This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-07-21
Channels
- # announcements (1)
- # babashka (13)
- # beginners (85)
- # calva (1)
- # chlorine-clover (16)
- # cider (30)
- # clj-kondo (2)
- # clj-on-windows (5)
- # cljdoc (3)
- # cljs-dev (12)
- # cljsrn (19)
- # clojure (88)
- # clojure-europe (39)
- # clojure-nl (7)
- # clojure-sweden (3)
- # clojure-uk (8)
- # clojurescript (35)
- # core-async (3)
- # data-science (2)
- # datomic (17)
- # defnpodcast (3)
- # deps-new (1)
- # editors (18)
- # emacs (4)
- # events (1)
- # expound (1)
- # figwheel-main (8)
- # fulcro (9)
- # graalvm (2)
- # graalvm-mobile (11)
- # helix (44)
- # jobs (7)
- # lsp (95)
- # luminus (9)
- # malli (6)
- # meander (4)
- # membrane (2)
- # missionary (13)
- # off-topic (98)
- # pathom (2)
- # polylith (4)
- # portal (3)
- # re-frame (6)
- # reagent (27)
- # reitit (3)
- # releases (3)
- # remote-jobs (6)
- # rewrite-clj (1)
- # rum (2)
- # sci (3)
- # shadow-cljs (7)
- # sql (66)
- # tools-deps (80)
- # vim (5)
- # xtdb (3)
Is there a magic incantation to get clj -X...
's :exec-fn
to return a status code to the shell? I want to use clj -X...
to execute my regression suite before a deploy but I need the bash script to check that the tests pass
It returns whatever the program you call with -X returns I believe. So it depends on what it is you are calling with it
That's what I thought but it's not working. I must be doing something wrong. Thanks for the confirmation
I might be wrong, I really just assumed so, maybe there's something weird with -X wrapping things
I'm not doing (System/exit ...) The function is just returning an integer
If you return an integer, I think that just goes to output. I think you need System/exit to set the process status code
That makes sense. Thx
Actually just returning an integer just has it go in the void lol. You need to print to have it go to the output. And (System/exit 0) or (System/exit 1) to set the status
The idea is that a "failed task" should generally throw an exception (an ex-info
for the best handling) and the CLI exec stuff will handle it.
Right now the return value is not used. It was when you could chain -X
functions (and I'm sure it will be again in the future -- like the ->
macro).
All my -X
functions return a hash map -- usually the hash map they were passed in, unless they have something to add it to. That makes them chainable/threadable. And they throw an exception if they "fail".
-X/-T should either return 0 for success or 1 if an exception is thrown out of the function
so depends on the test runner function to some degree
Right, but what was missing (in that thread) was understanding that what the invoked function returns does not affect the status -- I commented that you either throw an exception for failure or you just return data for success.
Would you say an explicit call to System/exit is bad practice inside a function meant to be called with -X or -T ?
Such functions should either return data or throw exceptions. In a world where functions can be chained (threaded), those functions should probably return the data they were passed as an argument, possibly with additional keys (or perhaps they should remove some of the keys they were given).
(I think it's a bit odd to see some of the build functions just returning nil
right now but maybe when we get threading back those functions will either get updated to return their input data, or functions that return nil
will cause the threading code to pass the original input data along to the next function?)
a build is a thing you write for your project. if the build functions aren't parameterized, there's no reason to do so
Sure, the internal functions, but the entry points, which all get passed arguments... I guess it'll depend on how much folks would use threading/chaining -- assuming we get that feature back (I see :fns
in the latest clojure.run.exec
so it looks like we'll get it back?).
the entry points in most of the build scripts I've written are not parameterized
Right, but they still have to accept a single argument? Because that's the hash map of stuff coming from the command line...
It looks like -T
fails when there is no build.clj
file and using ns-defaults, but it works if using fully qualified on the command line:
{:paths ["src"]
:aliases
{:foo {:ns-default foo}}}
(ns foo)
(defn bar
[params]
(println "Foo Bar")
params)
> clojure -T:foo bar
Execution error (FileNotFoundException) at clojure.run.exec/requiring-resolve' (exec.clj:34).
Could not locate build__init.class, build.clj or build.cljc on classpath.
clojure -T:foo foo/bar
Foo Bar
That makes sense to me. In the first case you are asking it to resolve build/bar
and it can't because no build
ns file exists.
In the second case you are asking it to resolve foo/bar
and it loads a foo
ns file and resolves bar
within it.
It's not that "there is no build.clj
file" so much as you are asking for a ns that doesn't exist -- it's just the same as doing clojure -M -m no-such
and getting
(! 592)-> clojure -M -m no-such
Execution error (FileNotFoundException) at clojure.main/main (main.java:40).
Could not locate no_such__init.class, no_such.clj or no_such.cljc on classpath. Please check that namespaces with dashes use underscores in the Clojure file name.
where is build even coming from?
That's what I'm wondering too. The only thing is I did have it as ns-default build at first and then changed it, could it be some kind of caching issue?
try -Sforce ?
Hi, I want to use tools.build with this
io.github.clojure/tools.build {:git/tag "v0.1.4" :git/sha "169fef9"}
But tools.deps says Error building classpath. Library io.github.clojure/tools.build has missing :sha in coordinate.
My CLI version is Clojure CLI version 1.10.3.855
. Is there something I missed?that's the stable release - the new git dep coords are only in the latest prerelease
1.10.3.920 is latest
That’s the installer
Oh, I thought he had :ns-default build
but maybe not?
@doglooksgood You need the prerelease version for that format of coordinate
what's the best way to get a repl up with build.clj
on the classpath? is it just clj -A:build
and then eval the ns form? Load-file? Or is there a way to essentially get "."
on the classpath with -T
but not invoke a build function. Pretty simple problem to solve just making sure i didn't overlook something obvious
@doglooksgood The CLI. You need 1.10.3.912 at least.
@dpsutton what we do at work is clj -M:build -i build.clj -r
Clojure CLI prerelease 1.10.3.929 available • TDEPS-189 - Port -T changes to Windows scripts • Script cleanups in bash
Nothing big there, but if Windows users want to kick the tires, go for it
Is there anything non-Windows users might need to test in this update?
nothing specific, just cleaned up some dead code mostly in the bash
@alexmiller With tools.build.api/copy-dir
, the :replace
hash map would be stuff like {"{{version}}" "1.2.3", "{{username}}" "seanc"}
-- a hash map with strings for keys and values?
I realized that with a small wrapper around tools.build
I can create a really nice, stripped down version of clj-new
🙂
(and that answer just confirms what I was thinking about that)
It seems that copy-file
will overwrite a directory as a file, which I mean maybe is a cool feature, but I feel its unintuitive behavior, I've never used a linux command that behaved like this:
e.g.:
;; output was a directory, but it will now become the tempo.clj file after calling this copy-file
clojure -T:build-api copy-file :src '"./src/tempo.clj"' :target '"./output"'
You expected it to be in target?
Ya, my expectation was if you don't specify the filename in :target it uses the same filename as the source file. But I'd be okay with just failing saying output is a folder. Overwriting the folder to be the file seems dangerous
Also weird is if do:
;; src is a directory with files in them, output is an empty directory
clojure -T:build-api copy-file :src '"./src"' :target '"./output"'
Then copy-file succeeds, but nothing seemingly happens. Like output
is still an empty directory, and src
is stil a directory with files in it.as the docstring says, "Copy one file from source to target, creating target dirs if needed." perhaps you are looking for copy-dir?
The latter one doesn't copy or create anything, the former overwrites an existing folder
The latter I tested just to see what happens in that edge case. I think I'd expect a failure in that case, not a silent do nothing but succeed. Though well at least it's not destructive. But the former feel wrong, to overwrite a directory with a file? At least the doc-string I think should be explicit of it. Cause it's a very easy fat-finger incident I think
Anyway, just reporting on the behavior in case you weren't aware of those edge cases. If its by-design that's fine too.
@U0K064KQV While I too am a bit surprised that copy-file
overwrites an (empty) directory, I'm also sympathetic to the fact that it does it because a) it's called copy file, b) it has :src
and :target
args not :target-dir
. I think my preference would to add an :overwrite
arg, that defaults to true
and could be set to false
so it would throw an exception if :target
exists in any form.
The default behavior would still be to silently overwrite :target
, regardless of what it is, but if you want to be paranoid, you could use :overwrite false
, and you could decide whether to delete
the :target
and re-copy or whatever.
On the same subject, I'd also like to see :recurse false
and :throw-on-missing true
as options on delete
-- but all of these are just "nice to have" knobs and dials as far as I'm concerned: the core functionality does what is needed for build programs -- and you have
and interop if you need more.
What's annoying with the copy over the directory, is this: copy-file :src '"./src/foo.cls :target '"./output"' Now output has become a file. Someone checks and says, oh that's not what I wanted. So they try: copy-file :src '"./src/foo.clj :target '"./output/foo.clj"' And now it throws with an error saying output is not a directory. So it's really inconsistent you see. It doesn't have well defined semantics. So everything seems to be undefined behavior. I'd be okay if it always overwrote everything. If it always overwrote empty things. If it always overwrote the file but not directories. Or if it never overwrote anything. Now as it stands, you're kind of forced to just experiment and learn all the undefined behaviors, which I assume would be different on different OS.
"So everything seems to be undefined behavior." -- that's a bit... melodramatic... 🙂
"I assume would be different on different OS" -- given that this is just Java I/O behavior, I'm not sure why you would assume that?
Under the hood, copy-file
is just this Java call: https://github.com/clojure/tools.build/blob/master/src/main/clojure/clojure/tools/build/util/file.clj#L59 -- so this is the semantics of Java's standard library itself.
And these are the only options it provides: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/nio/file/StandardCopyOption.html @U0K064KQV
Bottom line: t.b.api/copy-file does exactly what Java's Files/copy
command does, with the sole addition of calling (.mkdirs target-file)
to auto-create any missing directories in the :target
path.
I was thinking might be different because it exposed a: > sun.nio.fs.UnixCopyFile/copy exception And the name of that made me think it could be OS specific. Seems from the javadoc that file attributes are OS specific and undefined how they will copy, but the rest should be same.
Meh, ok, I guess this is just how nio copy works with REPLACE_EXISTING option, java is dumb 😛
"java is dumb" good, "clojure is dumb" bad :rolling_on_the_floor_laughing: