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

Developer Documentation #189

Merged
merged 4 commits into from
Sep 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Contributing Fixes

If you are interested in writing code to fix issues, please check the following content to see how to set up the developing environment.
If you are interested in writing code to fix issues, please check the following content to see how to set up the developing environment. If you are interested in understanding how the Gradle Build Server works under the hood visit the [developer documentation](./docs/developer.md).

### Requirement

Expand Down
29 changes: 14 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ JDK 17 or higher is required to build and launch the Build Server for Gradle.
## Supported Requests

Following BSP requests are supported in the current implementation:

- `build/initialize`
- `build/initialized`
- `build/shutdown`
Expand All @@ -26,45 +27,43 @@ Following BSP requests are supported in the current implementation:
- `workspace/buildTargets`
- `workspace/reload`


## Architecture

See [ARCHITECTURE.md](./ARCHITECTURE.md)

## Launch the Build Server for Gradle

### Specify the Plugin Location

The main class of the build server is `com.microsoft.java.bs.core.Launcher`. When you launch the server, you need to specify the location of the Gradle plugin via the system property `plugin.dir`. By default, you will find the plugin jar at `server/build/libs/plugins/plugin-${version}.jar` after building the project.

### Preferences

A [Preferences](./server/src/main/java/com/microsoft/java/bs/core/internal/model/Preferences.java) object can be put into the data field of the `build/initialize` request for customization. Please check the comments in the code for the meaning of each preference.

### Transport Method

The Gradle Build Server supports two types of transport methods: standard input/output and named pipe (unix socket). By default, the server uses the standard input/output transport if no arguments are specified.

To use the named pipe (unix socket) transport, start the server with the argument `--pipe=<pipeName>`. If the `--pipe=` option is provided but `pipeName` left empty, the server defaults to using the standard input/output transport.

## Contributing

This project welcomes contributions and suggestions. Most contributions require you to agree to a
Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.
This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.

When you submit a pull request, a CLA bot will automatically determine whether you need to provide
a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions
provided by the bot. You will only need to do this once across all repos using our CLA.
When you submit a pull request, a CLA bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA.

This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.

Please check [CONTRIBUTING.md](./CONTRIBUTING.md) for more details about how to setup and develop the project.

## Developer Documentation
jdneo marked this conversation as resolved.
Show resolved Hide resolved

Assisting documents to explaining the working of Gradle Build Server can be found in [developer documentation](./docs/developer.md). This will be helpful for you if you're planning to integrate Gradle Build Server or contribute to the project.

## Trademarks

This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft
trademarks or logos is subject to and must follow
[Microsoft's Trademark & Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general).
Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship.
Any use of third-party trademarks or logos are subject to those third-party's policies.
This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft trademarks or logos is subject to and must follow [Microsoft's Trademark & Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general). Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. Any use of third-party trademarks or logos are subject to those third-party's policies.

## Telemetry

Expand Down
91 changes: 91 additions & 0 deletions docs/android/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# ANDROID SUPPORT

Gradle Build Server provides initial support for Android projects with https://github.com/microsoft/build-server-for-gradle/pull/173

## Supported Features

- Languages: `Java`
- Project Types: `Application`, `Library`
- AGP Versions: [To be determined]

## Under the Hood: How it works?

We've leveraged the existing Java project support in Gradle Build Server and integrated it with Android development. We translate Android build variants (e.g., release, debug) into the Build Server Protocol's [build targets](https://build-server-protocol.github.io/docs/specification#buildtarget). We utilize the GradleSourceSet model, already used for Java projects, to store and manage Android build variant information. Here's a breakdown of the magic behind the scenes:

### 1. Project Detection:

Gradle Build Server detects if the Android plugin is applied to the project. It then uses the appropriate model builders to handle both Java and Android specifics.

![SourceSet build logic](../images/sourceset_build_logic.png)

### 2. Extracting Information:

We leverage reflection to gather necessary details about the project, such as compile tasks and dependencies. All the extracted data is used to build a `GradleSourceSet` model.

- We map Android variant's `assemble` task to the java sourceset's `classes` task, which ensures all resources and source code are compiled and packaged. This assemble task name follows the format `assemble<variant_name>`. E.g. `assembleRelease` for `release` variant and `assembleDebug` for `debug` variant.
- Java compile task responsible for compiling all the java code for the build variant follows a similar task name format `process<variant_name>JavaWithJavac`. E.g. `processReleaseJavaWithJavac` for `release` variant and `processDebugJavaWithJavac` for `debug` variant.
- Similar to Java projects, the `AndroidDependencyCollector` class handles module dependencies, including R files and Android SDK components.
- A build variant can have multiple source sets and each source set has java directories. We collect the list of these java directories which serve as the source directories.
- For the resource directories we take a similar approach of collecting the res and resource directories of the build variant's source sets.
- `processJavaResources` and `mergeResources` task provide the output directories of java and android resources.
- Using `javaCompile` task we fetch destination directory, compiler source directories and compiler args where the destination directory is used as `sourceOutputDirs`. Next we remove all the source directories from the compiler source directories to get the `generatedSourceDirs`.
- Classpath files for the variant is retrieved from the `compileConfiguration`.
- To determine if the variant has tests we check if android or unit tests are present in the given variant.
- Finally, we create the java extension using the compiler args we fetched earlier.

This integration allows Gradle Build Server to handle your Android projects just like any other Java or Scala project, ensuring a familiar and efficient workflow.

> [!NOTE]
> This is an ongoing effort, and future updates will expand Android support.

## Android Build Process: Relevant Part

The following diagram showcasing Android build process has been abstracted down to only show the parts which is relevant to this project's implementation.

![Android Build Process](../images/android_build_process.png)

## Known Limitations

### 1. Partial Intermediate Resources Support

Android generates a lot of intermediate sources such as AIDL, Render script, C/CPP, etc. Unfortunately AGP doesn't provide any APIs to retrieve these files. R file is one of these intermediate sources which is crucial for Android development so as a workaround we have retrieved the file using the process task for the build variant however, in some cases the task may not be registered during the sync in which case the dependency for R file is not provided.

**Issue:** https://github.com/microsoft/build-server-for-gradle/issues/181

### 2. Application and Library project Support

There are various kinds of projects that come under Android development such as `Application`, `Library`, `Instant App`, `Dynamic Modules`, `Android Test`, etc. We have added support for the most commonly used projects - `Application` and `Library` but the current implementation may require further enhancements to support other kinds of projects.

**Issue:** https://github.com/microsoft/build-server-for-gradle/issues/182

### 3. Test variants absent

Current implementation takes into account any user defined build variants and the default build variants - `debug` and `release` except the default test variants - test and androidTest. Test variants are different from the normal build variants and retrieving information from those requires further configurations.

**Issue:** https://github.com/microsoft/build-server-for-gradle/issues/183

### 4. No `ANDROID_HOME` fallback logic

Android Components to be used by an Android project is configured via `ANDROID_HOME` environment variable. If the property doesn't exist then we are not providing the dependency. This implementation can be improved via fallback logic similar to what we have for `JAVA_HOME` with https://github.com/microsoft/build-server-for-gradle/pull/165.

**Issue:** https://github.com/microsoft/build-server-for-gradle/issues/184

## Future Enhancements

- Support for more AGP versions

## Troubleshooting

If you face any issues with Android project support, please open a discussion for us to help. In case you find a bug in Android project support, please open an issue including the following information:

- Steps to reproduce
- Expected behaviour
- Actual behaviour
- Environment:
- Operating System
- BSP version
- AGP version
- Android project repository
- Error messages or logs

You can also request features by opening an issue.
39 changes: 39 additions & 0 deletions docs/developer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Developer Documentation

This documentation will assist developers trying to understand the working of the Gradle Build Server for easier contribution or integration.

## Composite Builds

### Challenge

When using a model builder to fetch the GradleSourceSet model, the complete hierarchical scope of the project is lost. This hinders the ability to fetch included builds and project dependencies, which is crucial for composite builds.

### Our Solution: Using Build Actions

To address this limitation we take the following approach:

1. We utilize the `BuildAction` to capture the complete hierarchical scope of the project, allowing us to retrieve all the included builds and their associated information.
2. After obtaining the included builds, we use the model builder to get source sets for each individual project.
3. With te complete set of source sets for each included build we map the build target dependencies and return the list of `GradleSourceSets`.

![Composite Build](./images/composite_build.png)

## Java Home Handling

The default `JAVA_HOME` configuration of a project maybe incompatible with Gradle Build Server. If this happens we implemented a fallback logic to find a compatible JDK to launch the Gradle Build Server.

1. We probe build the project and look for any `JAVA_HOME` incompatibility error.
jdneo marked this conversation as resolved.
Show resolved Hide resolved
- We probe build the project with `GradleBuild` model and check for a particular error message if a GradleException is thrown: `Could not create an instance of Tooling API implementation using the specified Gradle distribution` for incompatibility check.
- If the default configuration is incompatible we move to the next step.
2. We get the Gradle Java Home and check if it is compatible.
- If it is compatible then we use it and notify the client about the changed JDK usage.
- If it is incompatible we move to the next step.
3. We finally traverse through the list of JDKs retrieved from the preferences, and try to find a compatible `JAVA_HOME`.
- If a compatible JDK is found we use it and notify the client about the changed JDK usage.
- If we fail to find a compatible JDK we notify the client that we could not find a compatible `JAVA_HOME` to launch the Gradle Build Server.

![Java Home Handling](./images/java_home_handling.png)

## Android Support

See [docs/android/README.md](./android/README.md)
Binary file added docs/images/android_build_process.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/composite_build.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/java_home_handling.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/sourceset_build_logic.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading