-
-
Notifications
You must be signed in to change notification settings - Fork 358
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
WIP: Incremental build #1816
WIP: Incremental build #1816
Conversation
Hi @Egor18 thanks for your contribution here!
I vote for integrating it directly in Spoon: as we already stated, the current mechanism is broken in Spoon, so if you developed something which can be useful, go for it!
Yes, I changed that because the ".class" files were never taken into account and I wanted to avoid surprising clients. If you specify the parent directory of your classes as |
|
||
for (File classFile : classFiles) { | ||
String relative = mOldBinaryOutputDirectory.toPath().toAbsolutePath().relativize(classFile.toPath().toAbsolutePath()).toString(); | ||
String suffix = FilenameUtils.removeExtension(relative) + ".java"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How this trick works when you have a compilation unit with multiples classes? Or an inner class?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a good point, thanks. I'll try to make a better algorithm for matching .java files and .class files.
Also, if some file A.java was not changed, we need to add not only A.class into classpath, but all A$...class as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can also use: https://github.com/INRIA/spoon/blob/master/src/main/java/spoon/reflect/cu/CompilationUnit.java#L63. I added this function exactly for this purpose.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@msteinbeck, Thank you, that's very handy.
launcher.buildModel(); | ||
launcher.getModelBuilder().compile(SpoonModelBuilder.InputType.FILES); | ||
saveFactory(launcher.getFactory(), new File(binaryOutputDirectory, "model")); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should do some assertions here, to check that the factory is as expected.
List<File> incrementalSources = incrementalTool.getInputSourcesForIncrementalBuild(); | ||
String[] incrementalClasspath = incrementalTool.getClasspathForIncrementalBuild(); | ||
Factory incrementalFactory = incrementalTool.getFactoryForIncrementalBuild(); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment: you got a particular instance of IncrementalTool it could be great to assert it before continuing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, what do you mean by that? What exactly I should check about incrementalTool
?
|
||
FileUtils.deleteDirectory(PROJECT_DIR); | ||
PROJECT_DIR.mkdirs(); | ||
createFile(new File(PROJECT_DIR, "A.java"), "public class A { int x; }"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure why you don't put the resources files directly in Spoon: you could copy the resources in a temp dir for tests and apply your changes on the temp dir.
I do this to ensure that the JDT batch compiler is aware of my unmodified source files and, thus, is able to resolve dependencies that have been compiled in one of the previous iterations. In order to maximize speed, I compile the changed source files only. |
I really like your idea of serializing the factory into a file :). |
I added the new constructor for Launcher, that allows to perform an incremental build. Had to remove Also, I refactored tests and changed algorithm for matching .java files and .class files. |
|
||
@Test | ||
public void testIncremental() throws Exception { | ||
final File TEST_DIR = new File("./src/test/resources/inremental-test"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
inremental-test -> incremental-test
Still working on that. It's not really ready yet. I was testing incremental build on some real projects, and found some issues. |
OK added WIP in the PR title. |
Also could you add API documentation for the public methods? |
Hi. I'm working on incremental build (actually I'm implementing it again). C1.java:
C2.java:
For the first time, we build model from scratch and save it. After that, let's change type of the
Now we can build model incrementally, using previously saved model. I see few approaches:
So, what do you think? What is the best approach to update such type references? Are there any other approaches? |
From what I can tell, references are resolved lazily. Thus, you don't need to update unchanged files as their references will automatically point to the updated AST Nodes. |
@msteinbeck, In my example type references are resolved, but they refer to invalid old type |
Thanks for the follow up. Before adding new code, it may be a good idea to do an initial PR to first remove all code related to the completely broken 'build-outdated' feature. |
Moved to #1905 |
Hi. Since build-outdated-file feature is broken, I've implemented incremental build by myself thanks to @msteinbeck's concept (#1688 (comment)).
This implementation allows us to reuse the model from the previous build so, we need to rebuild only outdated sources. The model is serialized and stored in a file.
For now, I add incremental build as a test, but probably it can be integrated into spoon itself.
However, I have some question, considering incremental build.
Is it really necessary to add .class files of unmodified types into source classpath of a new build, even when we reuse the old Factory?
I added .class files in spoon 6.0.0. and it worked fine, but in spoon 6.2.0 I got InvalidClassPathException(".class files are not accepted in source classpath.")
So, I simply commented out addition of .class files in this PR, because it seems, that it does not affect anything, and my tests are passed.
What do you think?
Thank you.