Skip to content
New issue

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

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

Already on GitHub? # to your account

What does ShadeRule.keep do exactly? Does *anyone* know? #265

Open
benhutchison opened this issue Aug 3, 2017 · 5 comments
Open

What does ShadeRule.keep do exactly? Does *anyone* know? #265

benhutchison opened this issue Aug 3, 2017 · 5 comments

Comments

@benhutchison
Copy link

"The ShadeRule.keep rule marks all matched classes as "roots". If any keep rules are defined all classes which are not reachable from the roots via dependency analysis are discarded when writing the output jar. This is the last step in the process, after renaming and zapping."

What does this mean? ...defined precisely enough that I could write a test to verify whether it works or not?

Actually it's from jarjars readme, and you get whatever it is that jarjar does. Jarjar makes no attempt to define the above functionality precisely. And despite dependency tracing being notoriously hard and subtle, it does not include any unit tests for depedency tracking, nor can I make much sense of the implementation.

My own observation is that it simply doesnt work, for any definition of "reachable from the roots via dependency analysis" that I'd find useful (eg like Proguard). For example, scala.Function1 was removed from my Scala codebase by the shading operation.

By documenting this as a feature of the (respected) sbt-assembly, is this plugin implicitly endorsing broken code?

@johnduffell
Copy link

I had the same issue, and after looking into it jarjar keep does work, however sbt-assembly calls jarjar in a way that is not useful for the keep command.
If you look at the source code:

Shader.shadeDirectory(jarRules, dest, log, ao.level)

you will see that jarjar is applied separately to the main source and each jar individually.
So the result is that it will assume that none of the code in the jar is used as none of the roots are present.
The fix would be to either separate the keep rules and run them after generating the fat jar, or you could run jarjar afterwards somehow on the output jar.
Hope that helps understanding and maybe someone can fix that.

@markehammons
Copy link

I've had the same issue with ShadeRule.keep. Setting the root of my project's code as something to keep, results in a jar that is very small, and is missing scala.collections.Seq. Hope this can be fixed soon.

@mal
Copy link

mal commented Aug 29, 2018

We've ended up adding a separate step post-assembly to call jarjar process independently to work around this. @eed3si9n would it be possible to provide something like an .inAssembly context to denote rules to be evaluated post-assembly?

It'd be really nice to assemble the fat jar and then slim it right down using a simple keep("org.package.Main").inAssembly rule or similar.

@ScalaWilliam
Copy link

How did you do this @mal , do you have a repo by any chance?

@mal
Copy link

mal commented Feb 19, 2021

So my extremely hazy recollection of this is that we built a fat jar normally with assembly, then (I believe) ran the jarjar tool as described (or close to) in #186 in order to get the list of classes required by our main, resulting in a slimmed list, and then used that output to manually create a set of as simple and as few keep(x).isAll rules as possible to cover all the necessary classes. This was a trial and error process of starting with a keep rule only for our main, examining the fat jar, determining what from the jarjar output had not been included, adding as broad (while still sane) rule as possible to cover that, and repeating this process until we were just packaging the minimum required.

From memory the result was about four keep rules (including the initial one for our main class) and a significantly smaller jar for our application which met the size requirements we were hoping to beat.

I would note that while this approach worked and fulfilled our needs, it was devised in the absence of any strong JVM ecosystem knowledge, and so (and I would hope) there might be far better ways of addressing this type of problem, especially two and half years later.

P.S. This was for a relatively small project using just a few select parts from a very large supporting lib, explaining the relatively few rules, and significant filesize saving - from memory we shed over 200MB from the initial fat jar! 😁

# for free to join this conversation on GitHub. Already have an account? # to comment
Projects
None yet
Development

No branches or pull requests

6 participants