Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/dev #111

Merged
merged 23 commits into from
Jul 24, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
88f6d03
Fixed compilation error
SlimerDude May 20, 2018
d8df4ba
A more correct readme
SlimerDude May 20, 2018
d7eab5e
Tell F4 to build pods in the project root dirs
SlimerDude May 30, 2018
9723250
Save F4 launch to workspace
SlimerDude May 30, 2018
ae9e287
Cache resolved pods to reduce on build churn
SlimerDude May 30, 2018
5a29c70
Use Fantom file API
SlimerDude May 31, 2018
e12ed0a
Correct build behaviour with regards to podOutDir
SlimerDude May 31, 2018
c3ac332
proj.name -> pod.dis, after talks with Andy proj.name is the wrong meta
SlimerDude Jun 1, 2018
0c024bd
Whitespace tidy
SlimerDude Jun 1, 2018
64e023a
When auto-completing ctors, also include the Type so we can autocompl…
SlimerDude Jun 1, 2018
73ce0b6
Add the simple case to Func autocompletes
SlimerDude Jun 1, 2018
f50db42
Only suggest facet Types when you've just typed '@'
SlimerDude Jun 1, 2018
ea040d9
Fix some .pod file locking issues when compiling Java code
SlimerDude Jun 2, 2018
f12e109
Removed project file refreshing post build to prevent projects contin…
SlimerDude Jun 3, 2018
452be99
Look for the Java source directory, it may be in the project and not …
SlimerDude Jun 3, 2018
4f6d6c4
podDis is a more descricptive name
SlimerDude Jun 3, 2018
aa48da0
Opted to change the default Fantom build directory to 'build/' to kee…
SlimerDude Jun 3, 2018
0e11d25
Code tidy
SlimerDude Jun 3, 2018
9c595e4
Pref page sentence no longer true
SlimerDude Jun 3, 2018
048aee0
Map pre-compile errors to build.fan
SlimerDude Jun 3, 2018
c8f34fd
New pods
SlimerDude Jun 3, 2018
2b31759
Whitespace tidy
SlimerDude Jun 8, 2018
46830b0
NPE bug fix
SlimerDude Jun 8, 2018
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
3 changes: 3 additions & 0 deletions com.xored.f4.astView/.settings/com.xored.f4.core.prefs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
eclipse.preferences.version=1
podOutputDir=./
useExternalBuilder=false
Binary file modified com.xored.f4.astView/f4astView.pod
Binary file not shown.
3 changes: 3 additions & 0 deletions com.xored.f4.builder.ui/.settings/com.xored.f4.core.prefs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
eclipse.preferences.version=1
podOutputDir=./
useExternalBuilder=false
Binary file modified com.xored.f4.builder.ui/f4builderUI.pod
Binary file not shown.
5 changes: 3 additions & 2 deletions com.xored.f4.builder.ui/fan/CompilerPreferencePage.fan
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,10 @@ class CompilerOptionsBlock : AbstractOptionsBlock {
override protected Control? createOptionsBlock(Composite? parent) {
composite := SWTFactory.createComposite(parent, parent.getFont, 2, 1, GridData.FILL_HORIZONTAL)

SWTFactory.createLabel(composite, "Pod output dir", 1)
SWTFactory.createLabel(composite, "Build directory", 1)
bindControl(SWTFactory.createSingleText(composite, 1), podOutputDir, null)
SWTFactory.createLabel(composite, "Directory should be relative to the project directory", 2)
SWTFactory.createLabel(composite, "Where pods are built, relative to the project directory.", 2)
SWTFactory.createLabel(composite, "The 'build.fan > podOutDir' setting (should it exist) overrides this value.", 2)

SWTFactory.createLabel(composite, "", 2)
bindControl(SWTFactory.createCheckButton(composite, "Use external compiler", null, false, 2), useExternalBuilderKey, null)
Expand Down
1 change: 0 additions & 1 deletion com.xored.f4.builder.ui/fan/EnvPreferencePage.fan
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,6 @@ class EnvOptionsBlock : AbstractOptionsBlock {
SWTFactory.createLabel(composite, "Pods are published to the selected Fantom environment...", 1)
SWTFactory.createLabel(composite, " - 'None' - pods are copied to %FAN_HOME%/lib/fan/", 1)
SWTFactory.createLabel(composite, " - 'util::PathEnv' - pods are copied to %FAN_ENV_PATH%/lib/fan/", 1)
SWTFactory.createLabel(composite, "Publish directory may be overridden by specifying 'outPodDir' in 'build.fan'", 1)

return composite
}
Expand Down
3 changes: 3 additions & 0 deletions com.xored.f4.builder/.settings/com.xored.f4.core.prefs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
eclipse.preferences.version=1
podOutputDir=./
useExternalBuilder=false
Binary file modified com.xored.f4.builder/f4builder.pod
Binary file not shown.
8 changes: 4 additions & 4 deletions com.xored.f4.builder/fan/ExternalBuilder.fan
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@ class ExternalBuilder : Builder {
out := launch(wc, consumer)

newPodFile := fp.projectDir + `${fp.podName}.pod`
podFile := fp.podOutFile
oldPodFile := fp.podOutFile

if (newPodFile.exists) {
if (newPodFile.uri != podFile.uri) {
consumer?.call("[DEBUG] Copying pod to ${podFile.osPath}")
newPodFile.copyTo(podFile, ["overwrite" : true])
if (newPodFile.uri != oldPodFile.uri) {
consumer?.call("[DEBUG] Copying pod to ${oldPodFile.osPath}")
newPodFile.copyTo(oldPodFile, ["overwrite" : true])
}

if (fp.prefs.publishPod) {
Expand Down
242 changes: 124 additions & 118 deletions com.xored.f4.builder/fan/InternalBuilder.fan
Original file line number Diff line number Diff line change
@@ -1,27 +1,20 @@
using f4core
using f4launching
using f4core::FantomProject
using f4core::FantomProjectManager
using f4core::LogUtil
using compiler
using concurrent

using [java]org.eclipse.debug.core::DebugPlugin
using [java]org.eclipse.debug.core::ILaunchConfigurationWorkingCopy
using [java]org.eclipse.debug.core::ILaunchManager
using [java]org.eclipse.dltk.launching::ScriptRuntime
using [java]org.eclipse.dltk.launching::AbstractScriptLaunchConfigurationDelegate
using [java]org.eclipse.jdt.launching::IJavaLaunchConfigurationConstants as JavaConsts
using [java]org.eclipse.jdt.launching::IRuntimeClasspathEntry
using [java]org.eclipse.jdt.core::JavaCore
using [java]org.eclipse.jdt.core::IJavaProject
using [java]org.eclipse.jdt.launching::JavaRuntime
using "[java]org.eclipse.core.externaltools.internal"::IExternalToolConstants as ExtConsts

using [java]com.xored.fanide.core::FanCore
using [java]org.eclipse.core.runtime::IPath
using [java]org.eclipse.core.runtime::Path
using [java]org.eclipse.core.runtime::NullProgressMonitor
using [java]org.eclipse.core.resources::ResourcesPlugin
using [java]org.eclipse.core.resources::IResource
using [java]java.io::File as JFile
using [java]java.util::HashMap as JHashMap

using [java]com.xored.fanide.core::JStubGenerator
Expand All @@ -35,12 +28,15 @@ class InternalBuilder : Builder {
static const Str pluginId := "com.xored.f4.builder"

override CompilerErr[] buildPod(|Str|? consumer) {
// Prepare temporary output directory for pod building
statePath := FanCore.getDefault.getStateLocation
projectPath := statePath.append("compiler").append(fp.podName)
root := projectPath.toFile
root.mkdirs
root.listFiles.each |JFile? f|{ f?.delete}
// compile pods in a temporary workdir: /.metadata/.plugins/com.xored.fanide.core/compiler/<podName>/
// if we build them in a dir that we have control over, there shouldn't be any file locking / permission errors
pluginState := FanCore.getDefault.getStateLocation
pluginDir := File.os(pluginState.toOSString).normalize
compileDir := pluginDir + `compiler/${fp.podName}/`

// make sure it's empty first
compileDir.create
compileDir.listFiles.each { it.delete }

resolvedPods := fp.resolvePods

Expand All @@ -53,7 +49,7 @@ class InternalBuilder : Builder {
// Without this, we get compilation errors similar to "pod not found: f4parser".
// These aren't actual dependencies and don't seem to be transitive dependencies.
// Note that adding them as actual project dependencies also solves the issue,
// Though I don't know why I'm loath to do so - hence these 3 little lines.
// But because I don't know why, I'm loath to do so - hence these 3 little lines.
FantomProjectManager.instance.listProjects.each |p| {
resolvedPods[p.podName] = p.podOutFile
}
Expand All @@ -80,7 +76,7 @@ class InternalBuilder : Builder {
input.baseDir = fp.projectDir
input.srcFiles = fp.srcDirs
input.resFiles = fp.resDirs
input.outDir = File.os(projectPath.toOSString)
input.outDir = compileDir
input.output = CompilerOutputMode.podFile
input.jsFiles = fp.jsDirs
input.meta = meta
Expand All @@ -90,55 +86,138 @@ class InternalBuilder : Builder {

errs := compile(input)
consumer?.call(logBuf.toStr)
if (!errs[0].isEmpty)

if (errs[0].size > 0)
// ensure dumb compiler errs like 'Cannot resolve depend: pod 'afBedSheet' not found' are mapped to build.fan
return errs.flatten.map |CompilerErr err -> CompilerErr| {
consumer?.call("[ERR] ${fp.podName} - ${err.msg}")
return err.file == "CompilerInput" ? CompilerErr(err.msg, bldLoc) : err
}

if (!fp.javaDirs.isEmpty)
errs.add(compileJava(consumer, projectPath, resolvedPods))

// Compare pod file in output directory to podFile in project and overwrite it if they are different
podFileName := `${fp.podName}.pod`
newPodFile := input.outDir + podFileName
podFile := fp.podOutFile
oldPodFile := fp.podOutFile
newPodFile := compileDir + `${fp.podName}.pod`

if (!fp.javaDirs.isEmpty)
errs.add(compileJava(consumer, compileDir, resolvedPods))

if (newPodFile.exists) {
if (isPodChanged(newPodFile, podFile)) {
consumer?.call("[DEBUG] Copying pod to ${podFile.osPath}")
newPodFile.copyTo(podFile, ["overwrite" : true])
jp := JavaCore.create(fp.project)
jp.getJavaModel.refreshExternalArchives([jp], null)
fp.project.refreshLocal(IResource.DEPTH_INFINITE, NullProgressMonitor())

// while isPodChanged() is not absolutely needed, I do see more build thrashing without it,
// especially when building F4 itself. Given F4 needs it's pods in the project root dir, it may
// due to Builder (superclass) doing a zero depth refresh
if (isPodChanged(newPodFile, oldPodFile)) {

// the old behaviour was thus (see below),
// but re-freshing (esp after we'd copied over new pod files)
// caused the entire project to re-build, and it would keep on
// rebuilding itself continuously and endlessly. Not ideal!
// The Builder (superclass) does a zero depth refresh anyway.

// // refresh Java stuff
// jp := JavaCore.create(fp.project)
// jp.getJavaModel.refreshExternalArchives([jp], null)
//
// // refresh Fantom stuff
// fp.project.refreshLocal(IResource.DEPTH_INFINITE, NullProgressMonitor())

// copy pod to outDir
consumer?.call("[DEBUG] Copying pod to ${oldPodFile.osPath}")
newPodFile.copyTo(oldPodFile, ["overwrite" : true])
}

// sometimes we re-build just to re-publish, so don't bother checking for pod changes
if (fp.prefs.publishPod) {
consumer?.call("[DEBUG] Publishing ${newPodFile.name}...")
fp.compileEnv.publishPod(newPodFile)
}

newPodFile.delete
}

// we often cannot delete the .pod file if we've been generating Java stubs (get an IOErr)
// so don't! Delete it when we build again - it all seems fine then.
// compileDir.delete
return errs.flatten

} catch (Err err) {
logger.err("Could not compile ${fp.podName}", err)
LogUtil.logErr(pluginId, "${err.typeof.qname} during build - ${err.msg}", err)
throw err

} finally {
(input.ns as F4Namespace)?.close
}
}

private CompilerErr[][] compile(CompilerInput input) {
caughtErrs := CompilerErr[,]
compiler := Compiler(input)

try compiler.compile
catch (CompilerErr e) caughtErrs.add(e)
catch (IOErr e) caughtErrs.add(CompilerErr(e.msg, null))
catch (Err e) {
LogUtil.logErr(pluginId, "${e.typeof.qname} during build - ${e.msg}", e)
caughtErrs.add(CompilerErr("${e.typeof.qname} ${e.msg} - see Error Log View for details", Loc("CompilerInput")))
}
return [caughtErrs.addAll(compiler.errs), compiler.warns]
}

private CompilerErr[] compileJava(|Str|? consumer, File compileDir, Str:File resolvedPods) {
jtemp := compileDir + `temp-java/`
podFile := compileDir + `${fp.podName}.pod`
jtemp.create

jmap := JHashMap()
resolvedPods.each |File file, Str key| {
jmap.put(key, file)
}

// stub generation often "locks" the pod file so it cannot be updated or deleted
// this happens more often when working from flash drives
// reading from a different .pod file at least lets us update the original (with the jstubs)
newPodFile := compileDir + `jstub/${fp.podName}.pod`
podFile.copyTo(newPodFile, ["overwrite":true])
JStubGenerator.generateStubs(newPodFile.osPath, jtemp.osPath, jmap)

classpath := fp.classpath.join(File.pathSep) { it.osPath }
javaFiles := listFiles(fp.javaDirs).join(" ") { "\"${it}\"" }
jp := JavaCore.create(fp.project)
wc := createJdkConfig("Javac configuration", "javac", jp)
wc.setAttribute(ExtConsts.ATTR_TOOL_ARGUMENTS, "-d \"${jtemp.osPath}\" -cp \"${classpath}\" ${javaFiles}")
launch(wc, consumer)

wc = createJdkConfig("Jar configuration", "jar", jp)
wc.setAttribute(ExtConsts.ATTR_TOOL_ARGUMENTS, "uf \"${podFile.osPath}\" -C \"${jtemp.osPath}\" \".\"")
launch(wc, consumer)

return CompilerErr#.emptyList
}

private ILaunchConfigurationWorkingCopy createJdkConfig(Str name, Str exec, IJavaProject jp) {
wc := createLaunchConfig(ExtConsts.ID_PROGRAM_BUILDER_LAUNCH_CONFIGURATION_TYPE, name)
fullExec := JavaRuntime.getVMInstall(jp).getInstallLocation.toStr + (Env.cur.os == "win32" ? "/bin/${exec}.exe" : "/bin/$exec")
wc.setAttribute(ExtConsts.ATTR_LOCATION, fullExec)
return wc
}

private Zip? safeZipOpen(File file) {
try return Zip.open(file)
catch return null
private Str[] listFiles(Uri[] uris) {
list := Str[,]
uris.each{
(fp.projectDir + it).walk {
if (ext == "java") list.add(osPath)
}
}
return list
}

private ILaunchConfigurationWorkingCopy createLaunchConfig(Str type, Str name) {
wc := DebugPlugin.getDefault.getLaunchManager.getLaunchConfigurationType(type).newInstance(null, name)
wc.setAttribute(ILaunchManager.ATTR_PRIVATE, true)
return wc
}

// ----

private Bool isPodChanged(File newPod, File oldPod) {
if (!oldPod.exists)
return true
Expand All @@ -157,18 +236,21 @@ class InternalBuilder : Builder {
newContent := newPodZip.contents
oldContent := oldPodZip.contents

if(newPodZip.contents != oldPodZip.contents) return true
if (newPodZip.contents != oldPodZip.contents) return true

return podContentChanged(newPodZip, oldPodZip)

} finally {
newPodZip?.close
oldPodZip?.close
}

return true
}


private Zip? safeZipOpen(File file) {
try return Zip.open(file)
catch return null
}

private Bool podContentChanged(Zip newPod, Zip oldPod) {
newContents := newPod.contents
oldContents := oldPod.contents
Expand All @@ -185,8 +267,8 @@ class InternalBuilder : Builder {
}

private Bool metaChanged(File newFile, File oldFile) {
Str:Str newProps := newFile.readProps.exclude |v, k| { k.startsWith("build.") }
Str:Str oldProps := oldFile.readProps.exclude |v, k| { k.startsWith("build.") }
newProps := newFile.readProps.exclude |v, k| { k.startsWith("build.") }
oldProps := oldFile.readProps.exclude |v, k| { k.startsWith("build.") }
return newProps != oldProps
}

Expand All @@ -200,82 +282,6 @@ class InternalBuilder : Builder {

return false
}

private CompilerErr[][] compile(CompilerInput input) {
caughtErrs := CompilerErr[,]
compiler := Compiler(input)

try compiler.compile
catch (CompilerErr e) caughtErrs.add(e)
catch (IOErr e) caughtErrs.add(CompilerErr(e.msg, null))
catch (Err e) {
LogUtil.logErr(pluginId, "${e.typeof.qname} during build - ${e.msg}", e)
caughtErrs.add(CompilerErr("${e.typeof.qname} ${e.msg} - see Error Log View for details", null))
}
return [caughtErrs.addAll(compiler.errs), compiler.warns]
}

private CompilerErr[] compileJava(|Str|? consumer, IPath projectPath, Str:File resolvedPods ) {
jtemp := projectPath.append("temp-java").toFile

jtemp.mkdirs
jtempPath := jtemp.getAbsolutePath
podFile := File.os(projectPath.append("${fp.podName}.pod").toOSString)

JHashMap jmap := JHashMap()
resolvedPods.each |File file, Str key| {
jmap.put(key, file)
}

JStubGenerator.generateStubs(podFile.osPath, jtemp.getAbsolutePath, jmap)
jp := JavaCore.create(fp.project)

wc := createJdkConfig("Javac configutation", "javac", jp)
IRuntimeClasspathEntry[] entries := JavaRuntime.computeUnresolvedRuntimeClasspath(jp)
entries = entries.map { JavaRuntime.resolveRuntimeClasspathEntry(it, jp) }.flatten
classpath := entries.map { getLocation }.add(jtempPath).join(File.pathSep)
javaFiles := listFiles(fp.javaDirs).join(" ") { "\"${it}\"" }
wc.setAttribute(ExtConsts.ATTR_TOOL_ARGUMENTS, "-d \"${jtempPath}\" -cp \"${classpath}\" ${javaFiles}")
launch(wc, consumer)

wc = createJdkConfig("Jar configuration", "jar", jp)
wc.setAttribute(ExtConsts.ATTR_TOOL_ARGUMENTS, "uf \"${podFile.osPath}\" -C \"${jtempPath}\" \".\"")
launch(wc, consumer)

|JFile file|? delFunc := null
delFunc = |JFile file| {
if (file.isDirectory) {
file.listFiles().each(delFunc)
file.delete
} else
file.delete
}
jtemp.listFiles().each(delFunc)
return [,]
}

private ILaunchConfigurationWorkingCopy createJdkConfig(Str name,Str exec, IJavaProject jp) {
wc := createLaunchConfig(ExtConsts.ID_PROGRAM_BUILDER_LAUNCH_CONFIGURATION_TYPE, name)
fullExec := JavaRuntime.getVMInstall(jp).getInstallLocation.toStr+(Env.cur.os == "win32" ? "/bin/${exec}.exe" : "/bin/$exec")
wc.setAttribute(ExtConsts.ATTR_LOCATION, fullExec)
return wc
}

private Str[] listFiles(Uri[] uris) {
list := Str[,]
uris.each{
(fp.projectDir + it).walk {
if (ext == "java") list.add(osPath)
}
}
return list
}

private ILaunchConfigurationWorkingCopy createLaunchConfig(Str type, Str name) {
wc := DebugPlugin.getDefault.getLaunchManager.getLaunchConfigurationType(type).newInstance(null, name)
wc.setAttribute(ILaunchManager.ATTR_PRIVATE, true)
return wc
}
}


Expand Down
Loading