Skip to content

Scala maven import external #473

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

Merged
merged 13 commits into from
Apr 13, 2018

Conversation

natansil
Copy link
Contributor

@natansil natansil commented Apr 4, 2018

Currently, there are limitations to using maven_jar + scala_import:

  1. artifact information (e.g. version) and dependency information are separated between repository rules and build rules.
  2. for cross-repo transitive dependencies there is the unintended consequences of trying to fetch the wrong transitive dependencies:
    Let's say we have repo-a and repo-b.
    repo-a depends on target foo from repo-b
    foo depends on bar-v1
    repo-a declares bar with v2
    bar-v1 brings baz
    bar-v2 no longer depends on baz
    with the current design, when bazel builds foo for repo-a, it looks in repo-a’s workspace and fetches bar-v2
    but it will look in build file of repo-b for dependencies of bar and will try to fetch baz and will fail (because bazis not declared in workspace of repo-a )

In order to solve these issues a new repository rule should be defined that will also declare the transitive dependencies. This way the dependencies will be fetched from the original repo and not from external repos.

The idea is to extend the work done by @jart for java imports

Optimally, in order to have as much code reuse as possible, we want to strive to have as much generic code as possible with a jvm_import_external (see original proposal here) template rule that will allow to use it with either java_import or scala_import.

For now, we will work on implementing scala_maven_import_external based off of java_import_external rule and change it in such a manner as to enable easy migration to jvm_import_external .

jvm_import_external will include params:
rule_name (e.g. java_import, scala_import)
load (load statement, e.g. load("//scala:scala_import.bzl", "scala_import"))
use_ijar (propagate args to underlying rules. This case scala_import )
sha256 - make it optional
maven - allow translation from artifact to jar url ( maybe should actually reside in maven_import_external rule)

WORKSPACE Outdated
java_import_external(
name = "com_google_guava_guava_21_0",
licenses = ["notice"], # Apache 2.0
jar_urls = [
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are these alternative urls for the same sha?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can mirror files if you need it. Not sure I follow.


"""Rules for defining external Java dependencies.

java_import_external() replaces `maven_jar` and `http_jar`. It is the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this just a temporary copy paste? can we not get this with a remote dependency?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can make the existing java_import_external serve your use case, if you'd prefer.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes this is a temporary copy paste.
We're starting out this way to validate the differences are indeed small instead of iterating between this repository and bazel itself.
The general plan is to generalize with as few changes as possible and then port 80%-90% of the code back to bazel

@ittaiz
Copy link
Contributor

ittaiz commented Apr 4, 2018

@natansil I don't have time now to do a complete review but WDYT about sharing here a bit more detail on what problem we're trying to solve and what are the gains we're trying to achieve? Also maybe a bit on intermediate solution vs longer term

@natansil
Copy link
Contributor Author

natansil commented Apr 5, 2018

@ittaiz updated the description along the lines we discussed.
@johnynek I hope the new description will shed more light about what we are trying to achieve here.

@@ -4,7 +4,7 @@ load("//scala:scala_import.bzl", "scala_import")
#Many jars
scala_import(
name = "guava_and_commons_lang",
jars = ["@com_google_guava_guava_21_0//jar:file", "@org_apache_commons_commons_lang_3_5//jar:file"],
jars = ["@com_google_guava_guava_21_0//:file", "@org_apache_commons_commons_lang_3_5//jar:file"],
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ittaiz re-posting my question right next to the example of the consumer:

currently java_import_external does not support depending on the jar file directly. in order to not do major changes to justine's code, I've had to change the usage label structure from @com_google_guava_guava_21_0//jar:file to @com_google_guava_guava_21_0//:file.
Is this legitimate or should I re-write the code to have the same folder structure as maven_jar?

Alternatively, you've stated that scala_import can depend on full jar files without needing the file filegroup target.

so with the example above, I can just change it to
jars = ["@com_google_guava_guava_21_0//jar", "@org_apache_commons_commons_lang_3_5//jar"],

and that will solve the issue (and still not take ijars)?

@natansil
Copy link
Contributor Author

natansil commented Apr 9, 2018

@ittaiz , @johnynek please review.
The changes made:

  • make the repo_rule write scala_import instead of java_import
  • introduce artifact + server
  • discuss possibility to extract a common "template" repo rule out of java_import_external and scala_maven_import_external

@jjudd
Copy link
Contributor

jjudd commented Apr 9, 2018

We at Lucid are currently working on the external dependency issue and were just about to implement a scala_import_external by extending java_import_external so this is a very well timed PR :) Thanks for your work on this!

I have a couple questions:

The original java_import_external uses jar_urls instead of server_urls and artifact. Do we want to use jar_urls here? My thought is that we could use bazel-deps to resolve the maven dependencies, find the jar_urls and then produce a scala_import_external.

It seems like using bazel-deps would be quite nice: you can specify your dependencies in a file somewhere. Then import rules for those dependencies and all their transitive dependencies are generated.

This approach also works well with strict deps and unused deps. By using scala_import and java_import the generated import rules can declare their dependencies as deps instead of runtime_deps or exports.

How challenging would it be to create a generic jvm_import_external, which would be used to create java_import_external and scala_import_external? I'm hoping we could wrap java_import_external, as it is now, but pass in the rule you want it to produce: either java_import or scala_import.

If we create the jvm_import_external, do people want to use bazel-deps or is there a plan for Bazel to do something with Maven style dependencies without the need for a separate bazel-deps binary.

@natansil
Copy link
Contributor Author

@jjudd,

Regarding 1. + 2.

As I see it this is part of the modularity effort we want to achieve.
At the base will be jvm_import_external that accepts the underlying import rule name (java_import or scala_import or foo_import) and also special args these rules needs.
It will also still have jar_urls attr, as a more basic feature.

In addition we are thinking about something like a maven_import_external that has artifact arg that can potentially wrap jvm_import_external and resolve the jar urls.
Hopefully these rules will be able to be part of bazel repo itself.

Regarding 3. I think that Bazel's long-term goal is to have transitive deps resolution built-in, like explained here

@googlebot
Copy link

So there's good news and bad news.

👍 The good news is that everyone that needs to sign a CLA (the pull request submitter and all commit authors) have done so. Everything is all good there.

😕 The bad news is that it appears that one or more commits were authored or co-authored by someone other than the pull request submitter. We need to confirm that all authors are ok with their commits being contributed to this project. Please have them confirm that here in the pull request.

Note to project maintainer: This is a terminal state, meaning the cla/google commit status will not change from this state. It's up to you to confirm consent of the commit author(s) and merge this pull request when appropriate.

@ittaiz
Copy link
Contributor

ittaiz commented Apr 10, 2018

I consent to my contributions going in

ittaiz and others added 3 commits April 10, 2018 22:24
…or 'scala_maven_import_external', 'maven_import_external', 'java_import_external'
@natansil
Copy link
Contributor Author

extract common code to jvm_import_external rule. introduce macros for scala_maven_import_external,
'maven_import_external', (maven_import_external could in a later stage delegates to
jvm_maven_import_external with maven_import rule which has MavenCoordinates provider - this way artifacts can easily be known by consumers)
'java_import_external' (for regression)

jvm_import_external now allows optional load statements and any other additional attributes the underlying import rule needs
I still need to change the documentation.

def scala_maven_import_external(artifact, server_urls, **kwargs):
jvm_maven_import_external(
rule_name = "scala_import",
rule_load = "load(\"@io_bazel_rules_scala//scala:scala_import.bzl\", \"scala_import\")",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should probably be an attribute with a default value since some organizations (like us) add these in prelude and also some organizations (stripe?) might have aliases or stuff so they load from a different place

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

WORKSPACE Outdated
scala_maven_import_external(
name = "com_google_guava_guava_21_0",
licenses = ["notice"], # Apache 2.0
artifact = "com.google.guava:guava:21.0",
server_urls = ["https://mirror.bazel.build/repo1.maven.org/maven2"],
jar_sha256 = "972139718abc8a4893fa78cba8cf7b2c903f35c97aaf44fa3031b0669948b480",
)

# for regression testing purposes
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i don't understand this (even with the comment sorry!)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed a more detailed explanation. is this clear now?

@jjudd
Copy link
Contributor

jjudd commented Apr 11, 2018

Thanks for generalizing things into jvm_import_external. Can we add a scala_import_external that looks like java_import_external, i.e., it takes jarl_urls, jar_sha256, srcjar_urls, and srcjar_sha256?

I ask because I imagine not everyone will want to rely on scala_maven_import_external to do the maven resolution, especially considering that the rule doesn't support transitive dependencies right now.

I'm currently modifying bazel-deps to use java_import_external and scala_import_external (an internal version) instead of java_libraryandscala_import. bazel-deps resolves the jars, finds all the information it needs, and then writes the rule calls to a .bzl` file.

I'm happy to add the rule to this PR. I just wanted to get people's feedback.

@ittaiz
Copy link
Contributor

ittaiz commented Apr 11, 2018 via email

@jjudd
Copy link
Contributor

jjudd commented Apr 11, 2018

I have read through the code. I still see value in having a scala_import_external that is used in the same way as java_import_external. I would like to separate Maven resolution from artifact downloading until the Bazel community agrees on a Maven resolution solution.

Maven resolution is a pretty active area in Bazel without an agreed on solution. I know of bazel-deps, transitive_maven_jar, native maven_jar, skylark maven_jar, and rules_maven. This adds another option to that mix. I would like to be able to use scala_import_external without subscribing to a particular artifact resolution strategy.

You can implement scala_maven_import_external using scala_import_external more easily than the other way around. The current commit does this for jvm_maven_import_external and jvm_import_external:

def jvm_maven_import_external(artifact, server_urls, **kwargs):
  jvm_import_external(
      jar_urls = _convert_to_url(artifact, server_urls),
      **kwargs
  )

I'm suggesting that we have the same thing for Scala.

@ittaiz
Copy link
Contributor

ittaiz commented Apr 11, 2018 via email

@natansil
Copy link
Contributor Author

added scala_import_external
@jjudd

@natansil natansil changed the title [WIP] Scala maven import external Scala maven import external Apr 12, 2018
Copy link
Contributor

@ittaiz ittaiz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!
@johnynek any objections to this being merged?
Next step will be to open an issue to bazel linking to this code and suggesting we send it upstream (without the scala macros obviously)

@natansil natansil force-pushed the scala_maven_import_external branch from 99d476b to e4472ea Compare April 12, 2018 15:32
@jjudd
Copy link
Contributor

jjudd commented Apr 13, 2018

Thanks so much for adding scala_import_external @natansil and @ittaiz!! I used it in our bazel-deps work today and so far things are working great! 😃

@ittaiz
Copy link
Contributor

ittaiz commented Apr 13, 2018

@johnynek I'll merge in a couple of hours if you don't ping back

@ittaiz ittaiz merged commit 4afc7ab into bazel-contrib:master Apr 13, 2018
bazel-io pushed a commit to bazelbuild/bazel that referenced this pull request May 29, 2018
This PR copies "upstream" a change made to java_import_external in`rules_scala` (see [PR](bazel-contrib/rules_scala#473))

This change was originally proposed by @dslomov [here](#3528) (search for 'jvm_import_external')

java_import_external was changed to `jvm_import_external` 'template like' rule + `java_import_external` macro in order to allow for other jvm languages (e.g. scala and kotlin) to utilize the 'import_external' functionality without copying the boiler plate again and again.

This has already been used in `rules_scala` with the introduction of `scala_import_external` and `scala_maven_import_external`

In addition to the `import rule name`, `jvm_import_external` can also be called with custom attributes needed by the underlying import rules, as well as a custom load statement.

`java_import_external` is used as a macro in rules_scala to make sure it's still functioning properly after the change.

`jvm_maven_import_external` exposes maven artifact terminology.
This will also allow to create a `maven_import_external` macro that will delegate to `jvm_maven_import_external` with a `maven_import` rule which will have `MavenCoordinates` Provider as discussed [here](#4654)

Closes #5068.

PiperOrigin-RevId: 198398621
ianoc-stripe pushed a commit to ianoc-stripe/rules_scala that referenced this pull request Jun 12, 2018
* original jave_import_external

* allow for direct jar file usage in dependencies

* change java_import to scala_import

* replace jar_urls with artifact + server_urls

* remove filegroup target and use maven_jar for specific places that need files directly. an issue will be open for scala_import to support direct file output

* rename to scala_maven_import_external. still need to decide on splitting to jvm_import_external/maven_import_external

* _concat_with_needed_slash

* fix typo

* add 'return' in new method

* extract common code to 'jvm_import_external' rule. introduce macros for 'scala_maven_import_external', 'maven_import_external', 'java_import_external'

* CR changes

* added documentation

* moved license notice back to the top
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants