Fork me on GitHub
#clojure
<
2023-10-15
>
sheluchin15:10:14

Is there a way to get from a git lib name (`:git/lib`) to the Maven library name?

Alex Miller (Clojure team)15:10:08

they don't have any necessary relationship, so no

Alex Miller (Clojure team)15:10:28

assuming there even is a Maven library name

sheluchin15:10:53

I understand that sometimes there isn't a relationship, but for cases when there is, I'd like to be able to make the connection. I'm ultimately looking for a way to determine from a lib repo's GitHub URL whether that lib is used as a dependency in a sample deps.edn file.

Alex Miller (Clojure team)15:10:10

published maven artifacts usually have scm info in their pom (always for Maven central) which may include the github url

Alex Miller (Clojure team)15:10:12

so you could look up the pom for every Maven dep, and check it's scm url

Alex Miller (Clojure team)15:10:06

for example, tools.build has both. in it's pom https://repo1.maven.org/maven2/io/github/clojure/tools.build/0.9.6/tools.build-0.9.6.pom there is <scm><url> of [email protected]:clojure/tools.build.git

sheluchin15:10:04

If that info isn't there, is it reasonable to assume that the :git/lib name is the predominant way the library would be included in the deps.edn file?

sheluchin15:10:40

@U0NCTKEV8 aren't the options just git, local, and Maven? Why isn't it a reasonable assumption?

hiredman16:10:38

Neither of those options is a monolith

hiredman16:10:48

There are many repos, many git repos, scm is optional, maven group and artifact name has no relation to git repo url

hiredman16:10:58

Git is a dvcs, etc

sheluchin16:10:44

For the sake of simplicity I'm only dealing with GitHub repos for now.

oyakushev16:10:57

As Alex said, Maven's pom -> Github repo is kinda possible sometimes. The other way around is not quite.

sheluchin16:10:39

Yeah, I think the Clojars feed file contains that particular connection most of the time. https://github.com/clojars/clojars-web/wiki/Data#useful-extracts-from-the-poms

oyakushev16:10:34

You can, hypothetically, search Clojars using the name of the Github repo as the query, then iterate over all responses (as there could be several of them) and check for <scm> tag in the pom if you can get a match.

oyakushev16:10:18

If "best effort" is a good enough accuracy for you, then this might work.

sheluchin16:10:07

I'm thinking to use that POM extract info from Clojars as first priority, followed by the assumption that the :git/lib as a second priority is the most likely candidate, and calling it a day from there. Does it seem like a fair heuristic? Best effort is indeed the criteria.

oyakushev16:10:25

I didn't quite understand what are your inputs, tbh. What info do you have and what do you need to obtain?

sheluchin16:10:57

I have a list of Clojure libraries hosted on GitHub and their GitHub URL, along with a sample deps.edn file. I want to understand which of the libraries is being used in the deps.edn file. Essentially, for some particular Clojure project with a deps.edn file, I'm trying to determine the GitHub URLs of its dependencies, when available. I recognize that it's not always available. I'm using the Clojars feed with POM extracts as a helper source.

oyakushev16:10:20

I see. Then, all the dependencies in that deps.edn file would either be io.github.* which immediately gives you the repo, or a :mvn/version dependency that you can download a POM file for, parse it as XML, and search for <scm> or <url> tag.

oyakushev16:10:02

In fact, might not even parse it, but just dumb-search the pom for

oyakushev16:10:14

Just FYI, don't even need to use any special API, poms can be obtained by direct URL, e.g. https://repo.clojars.org/cheshire/cheshire/1.0.2/cheshire-1.0.2.pom

sheluchin16:10:36

Thanks everyone. Appreciate your input.

flowthing17:10:09

Why does calling .fexpr throw an error when extending a protocol but work when not?

oyakushev17:10:50

This is very interesting. I think what happens is that in the first case, you are calling a method fexpr() (via reflection), and in the second case it tries to access a field, which is private.

oyakushev17:10:22

Using clj-java-decompiler:

(decompile (.fexpr invoke-expr))

...
    public static void load() {
        Reflector.invokeNoArgInstanceMember(cjd__init.__user_invoke_expr.getRawRoot(), "fexpr", false);
    }

oyakushev17:10:06

(decompile (extend-protocol P clojure.lang.Compiler$InvokeExpr (f [this] (.fexpr this))))

...

    public static Object invokeStatic(final Object this) {
        return ((Compiler.InvokeExpr)this).fexpr;
    }

oyakushev17:10:29

My bad, there is no fexpr() method there. But the difference is certainly in reflection.

oyakushev17:10:46

See the difference between:

user=> (clojure.lang.Reflector/getInstanceField invoke-expr "fexpr")
#object[clojure.lang.Compiler$FnExpr 0x7a1f45ed "clojure.lang.Compiler$FnExpr@7a1f45ed"]

user=> (.fexpr ^clojure.lang.Compiler$InvokeExpr invoke-expr)
Execution error (IllegalAccessError) at user/eval7288 (REPL:1).
tried to access class clojure.lang.Compiler$InvokeExpr from class user$eval7288

flowthing17:10:27

Thanks! That makes sense. I should've thought of decompiling. 🙂 Except that I thought that fexpr was public, but I must've misread.

oyakushev17:10:33

It looks like, having default visibility for a nested class prevents normal access to it while letting reflective access.

oyakushev17:10:56

fexpr is indeed public, but the nested static InvokeExpr has default visibility

flowthing17:10:02

Yes, you're right. 👍

flowthing17:10:38

Very helpful, thanks! Looks like I have to manually reflect when extending the protocol, then.

👍 1
oyakushev17:10:34

It's a weird interaction you've discovered, saving this for some conference gotcha/puzzler in the future 😄

flowthing17:10:56

Heh, glad something useful came of it. ðŸĪŠ

âĪïļ 1
hiredman17:02:17

when doing the reflective lookup it is code in the clojure.lang package that is doing it, but when not doing it reflectively the compiled code doesn't live in the clojure.lang package

Sahil Dhanju19:10:01

Are there any good resources/blogs/videos that take you through how the clojure compiler works?

Bobbi Towers21:10:57

There's a decent list here: https://clojureverse.org/t/resources-for-learning-how-the-clojure-compiler-works/9059 (well, by "decent", what I mean is "this seems to be all there is") The last link, the video with Mike Fikes, is extremely good, but it's about the Clojurescript compiler. If you find that useful, you'll also enjoy Fogus' Clojurescript Anatomy talk, and accompanying blog posts

âĪïļ 1