-
Notifications
You must be signed in to change notification settings - Fork 5k
Working with files docs #4293
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
Working with files docs #4293
Conversation
I have started the chapter with a series of common tasks that users want to accomplish with files. The aim is to answer some commonly asked questions while directing readers to more detailed information so that they have a broader understanding of the topic.
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.
Hi Peter,
I ran over the preliminary content and left a couple of comments. Overall, the content is already much better than before. I am going to give a more thorough pass when you think the changes are in a somewhat final state.
== Working With Files | ||
|
||
Most builds work with files. Gradle adds some concepts and APIs to help you achieve this. | ||
Almost every Gradle build works with files: think source files, library dependencies, reports and so on. That's why Gradle comes with a comprehensive API that makes it simple to achieve common tasks. |
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.
Instead of "library dependencies" we settled on the term "file dependency". See https://docs.gradle.org/nightly/userguide/declaring_dependencies.html#sec:declaring_file_dependency for example.
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.
- Use "file dependency" in place of "library dependency"
== Working With Files | ||
|
||
Most builds work with files. Gradle adds some concepts and APIs to help you achieve this. | ||
Almost every Gradle build works with files: think source files, library dependencies, reports and so on. That's why Gradle comes with a comprehensive API that makes it simple to achieve common tasks. |
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.
In this section we can probably be more concrete. I'd say "file operations" instead of "common tasks".
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.
- Be more concrete and less ambiguous than "common tasks"
|
||
You copy a file by creating an instance of Gradle's builtin api:org.gradle.api.tasks.Copy[] task and configuring it with the location of the file and where you want to put it. This example mimics copying a generated report into a directory that will be packed into an archive (zip, tarball, or whatever): | ||
|
||
---- |
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.
All code samples should be an embedded code snippet from an actual build script under docs/src/samples
. Furthermore, all of them should be tested e.g. underneath integ-test/src/integTest/groovy/org/gradle/integtests/samples
.
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.
Understood. I simply wanted to get the text done first. BTW, are there any instructions for running the docs integration tests or a subset of them? I remember working it out last year, but have of course forgotten and can't find any info on it.
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.
- Turn code examples into tested samples
- Update existing samples to use best practice and reflect their corresponding points as succinctly and well as possible
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.
There are two types of tests you can run:
- The
UserGuideSamplesIntegrationTest
which basically only verifies that the expected output has been produced according to the*.out
that follow the naming convention of the sample ID. Instructions are in the comment of the test class. - The corresponding integration test(s) that execute the sample code and make assertions about the outcome. One example is
SamplesDeclaringDependenciesIntegrationTest
. After extracting the samples (as described in 1) you can just run it from the IDE. It's possible that they do not exist for this page. I'd set up a new test class if it doesn't exist yet.
When reworking content in the dependency management chapter I have been leaning mostly toward 2 as it provides a way verify more than just the output.
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.
I'm running into an issue trying to execute the dedicated integration tests from IntelliJ:
java.lang.ExceptionInInitializerError
at org.gradle.integtests.fixtures.AbstractIntegrationSpec.$spock_initializeFields(AbstractIntegrationSpec.groovy:56)
Caused by: org.gradle.internal.service.ServiceCreationException: Could not create service of type ClassLoaderRegistry using GlobalScopeServices.createClassLoaderRegistry().
at org.gradle.integtests.fixtures.executer.AbstractGradleExecuter.<clinit>(AbstractGradleExecuter.java:92)
... 1 more
Caused by: java.lang.IllegalArgumentException: Cannot find JAR 'slf4j-api-1.7.16.jar' required by module 'gradle-core' using classpath.
at org.gradle.api.internal.classpath.DefaultModuleRegistry.findDependencyJar(DefaultModuleRegistry.java:254)
... 9 more
I imported the the project after running ./gradlew idea
. Not sure what else I need to do. Any ideas?
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.
Hhhm, doesn't sounds familiar. Can you try the following?
- Run
./gradlew cleanIdea idea
from the command line. Do not import the project by pointing to the rootbuild.gradle
file. There're still some things that don't work properly yet with the built-in Gradle import functionality. Just open the generatedgradle.ipr
file. - Run
./gradlew intTestImage
from the command line. - Run the test from the IDE.
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.
Thanks. I ran into another issue with a conflicting groovy-all
library, but hacked that to get the tests running from within the IDE.
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.
OK, great. Saw your question on the channel. Looks like it was a bug.
|
||
We look at these parts in more detail later in the chapter, but we'll start with how you accomplish some of the most common tasks users need. | ||
|
||
=== Copying a single file |
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.
I think it would make sense to also explain the from
/into
methods to a certain extent.
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.
Agreed, although I'll keep it minimal. Now that I have the later sections in place, it will be easier to reference them appropriately.
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.
- Explain what
from()
andinto()
do/are for
Note that hardcoding paths like this makes the build brittle. It's better to use the task that generates a file as the source of the file's location. In this modified example, we use a report task defined elsewhere that has the report's location stored in the `outputFile` property: | ||
|
||
---- | ||
ext.archiveDir = file("${buildDir}/toArchive") |
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.
I'd define the extra property for the task and not the project. That will provide a narrower context and can only be used with the reference of this specific task. Ultimately, it avoids introducing global properties which makes the build harder to maintain.
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.
Agreed. I was thinking in terms of a generic directory where all archives are put, but that's not the case here. It's specific to this task.
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.
- Move project property onto the task
|
||
---- | ||
task packageDistribution(type: Zip) { | ||
archiveName = "my-distribution.zip" |
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.
Maybe we should promote the use of the base
plugin here instead as it provides the conventions.
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.
Since there are two examples, I'd like to have one without the plugin, to demonstrate that it's not needed, and one with to show the convenience. I'll probably trim this section a bit too, as I've now updated the in-depth section on creating archives which covers the base
plugin and naming conventions in detail.
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.
- Use one sample without the Base Plugin, and one with
} | ||
---- | ||
|
||
=== Moving files and directories |
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.
Good to spell it out!
} | ||
---- | ||
|
||
As you can see, you can have multiple `from()` declarations in a copy specification, each with its own configuration. |
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.
We should have a section that explain the file operation methods on Project
(e.g. project.copy
) and the difference between the task types and the methods.
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 was already in the chapter, but I've updated it. You'll find it in the File Copying in Depth section. It's actually focused on the copy()
method, but now you mention it, there isn't anything on delete()
or its corresponding task right now. Are there any others I should cover?
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.
Add information on the following:
-
Delete
task and method -
sync()
method
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.
I can only think of Project.mkdir()
and Project.delete()
right now. I don't think we need to show examples for all of them. It's probably OK to just list them and link to the DSL guide.
|
||
One thing to note is how the `include()` directive applies only to the `from()`, whereas the directive in the previous section applied to the whole task. These different levels of granularity in the copy specification allow you to easily handle most requirements that you will come across. TODO: Link to more details on copy specs. | ||
|
||
=== Creating archives (zip, tar, etc.) |
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.
Frequently asked about on the user forum: How do I create an uberjar? It would be helpful to explain it here.
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.
Good idea. If it's that frequently asked, it might make sense to include it as one of the early examples in the chapter, with perhaps some more detail in the in-depth section.
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.
- Provide an example on creating an uber JAR
@bmuschko Do you mean one in which the contents of the other JARs are included in the fat JAR, or the JARs themselves are included as is in the fat JAR (the Spring Boot approach — or at least it was).
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.
I meant 1. For example:
task uberjar(type: Jar) {
from zipTree(jar1)
from zipTree(jar2)
}
2 is similar except that the contents of the JAR files (to be included) are not extracted via zipTree
.
|
||
This is not a common requirement and should be used sparingly as you lose information and can easily break a build. It's generally preferable to copy directories and files instead. | ||
|
||
=== Renaming files on copy |
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.
One example on more complex processing would be great as well e.g. the use of eachFile
.
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.
Is there a common scenario for users in which something like eachFile()
is the best solution? Or is it only for specialised cases?
@bmuschko @eriwen Are we using the guides style guide on the user manual? Is there another document? I hate not knowing how to refer to plugins by name, whether to capitalize archive format names, and so on. |
The guides style guide contains some good advice. I don't think we have been following it in the past when writing user guide content. It would make sense to enhance the style guide by additional rules and then use it across the board. @eriwen Any additional thoughts? |
subprojects/docs/docs.gradle
Outdated
|
||
attributes website: 'http://www.gradle.org' | ||
attributes website: 'http://www.gradle.org', | ||
javaApi: 'https://docs.oracle.com/javase/8/docs/api' |
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.
We might want to reference the Java 7 docs here as we still supporting it as the minimal JDK version.
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.
I'm fine with that. One of the reasons I made it a document attribute :)
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.
- Reference Java 7 API docs rather than Java 8
DO NOT MERGE!
This is a series of changes to the Working With Files chapter of the user guide that I'm collecting into a pull request to make reviewing easier. Hopefully the changes will eventually propagate to the user guide, but for now they should not be merged.