Fork me on GitHub
#beginners
<
2019-09-03
>
seancorfield00:09:08

(renamed to match what you started to write just above)

johnjelinek00:09:26

there's no state, so:

(ns hello-cdk.hello-stack
  (:gen-class
   :extends software.amazon.awscdk.core.Stack
   :constructors {[software.amazon.awscdk.core.Construct String] [software.amazon.awscdk.core.Construct String software.amazon.awscdk.core.StackProps]
                  [software.amazon.awscdk.core.Construct String software.amazon.awscdk.core.StackProps] [software.amazon.awscdk.core.Construct String software.amazon.awscdk.core.StackProps]}
   :init init)
  (:import (software.amazon.awscdk.core Construct Stack StackProps)
           (software.amazon.awscdk.services.s3 Bucket BucketProps)))

(defn -init
  ([parent id] [[parent id nil] []])
  ([parent id props] [[parent id props] []]))

johnjelinek00:09:38

seems to load ... now I'm gonna try to require it in

seancorfield00:09:06

You may want nil instead of [] for the state value. Or it just may not care.

johnjelinek00:09:07

I'll try that out

seancorfield00:09:16

Part of the confusion comes from a lot of the examples using strings where a plain symbol is supposed to be used -- and the specs added in Clojure 1.9 enforce that now.

seancorfield00:09:14

See, for example, the user-submitted code example given here https://clojuredocs.org/clojure.core/gen-class (and compare it to the second one).

johnjelinek00:09:14

for these things that are (:gen-class'd , do I not (:require them? Maybe I (:import them?

johnjelinek00:09:31

cuz' I'm getting ClassNotFoundException when I (:require

seancorfield00:09:41

You're generating Java class so you import them

👍 1
seancorfield00:09:49

(or :import in the ns form)

johnjelinek00:09:03

hmm ... doesn't like the (:import:

Syntax error macroexpanding clojure.core/ns at (src/hello_cdk//Users/johnjelinek/Documents/code/hello-cdk/src/hello_cdk/app.clj:1:1).
() - failed: Insufficient input at: [:ns-clauses :import :classes :package-list :classes] spec: :clojure.core.specs.alpha/package-list
(hello-cdk.hello-stack) - failed: simple-symbol? at: [:ns-clauses :import :classes :class] spec: :clojure.core.specs.alpha/ns-import
:import - failed: #{:refer-clojure} at: [:ns-clauses :refer-clojure :clause] spec: :clojure.core.specs.alpha/ns-refer-clojure
:import - failed: #{:require} at: [:ns-clauses :require :clause] spec: :clojure.core.specs.alpha/ns-require
:import - failed: #{:use} at: [:ns-clauses :use :clause] spec: :clojure.core.specs.alpha/ns-use
:import - failed: #{:refer} at: [:ns-clauses :refer :clause] spec: :clojure.core.specs.alpha/ns-refer
:import - failed: #{:load} at: [:ns-clauses :load :clause] spec: :clojure.core.specs.alpha/ns-load
:import - failed: #{:gen-class} at: [:ns-clauses :gen-class :clause] spec: :clojure.core.specs.alpha/ns-gen-class

seancorfield00:09:29

And your :import looks like...?

johnjelinek00:09:11

(ns 
  (:gen-class)
  (:import (software.amazon.awscdk.core App)
           (hello-cdk hello-stack)))

(defn -main [& argv]
  (let [app (new App)
        stack (hello-cdk.hello-stack. [app "hello-cdk-1"])]
    (.synth app)))

seancorfield00:09:34

That second import is not legal

seancorfield00:09:12

You can't have - in Java packages or class names, and it expects (the.package.name TheClassName)

seancorfield00:09:08

I don't know what your generated class name will be (since you didn't specify :name)

johnjelinek00:09:29

trying to address that now 😄

seancorfield00:09:34

I'm guessing your package and class names might be (hello_cdk hello_stack) but I'm not sure...

johnjelinek00:09:17

hello_stack for sure

seancorfield00:09:54

And hello_cdk for the package! 🙂

johnjelinek00:09:49

(ns 
  (:gen-class)
  (:import (software.amazon.awscdk.core App)
           (hello_cdk hello_stack)))

(defn -main [& argv]
  (let [app (new App)
        stack (hello_stack. [app "hello-cdk-1"])]
    (.synth app)))
results in: >Syntax error (IllegalArgumentException) compiling new at (hello_cdk/app.clj:8:15). >No matching ctor found for class hello_cdk.hello_stack

johnjelinek00:09:19

but I have a 2-arity ctor defined (reference above)

johnjelinek00:09:07

reference:

(ns hello-cdk.hello-stack
  (:gen-class
   :extends software.amazon.awscdk.core.Stack
   :constructors {[software.amazon.awscdk.core.Construct String] [software.amazon.awscdk.core.Construct String software.amazon.awscdk.core.StackProps]
                  [software.amazon.awscdk.core.Construct String software.amazon.awscdk.core.StackProps] [software.amazon.awscdk.core.Construct String software.amazon.awscdk.core.StackProps]}
   :init init)
  (:import (software.amazon.awscdk.core Construct Stack StackProps)
           (software.amazon.awscdk.services.s3 Bucket BucketProps)))

(defn -init
  ([parent id] [[parent id nil] nil])
  ([parent id props] [[parent id props] nil]))

hiredman00:09:22

A vector is a single argument, not two

johnjelinek02:09:37

hmm ... something's not clicking right for me. I'm trying to transpose this:

package com.myorg;

import software.amazon.awscdk.core.Construct;
import software.amazon.awscdk.core.Stack;
import software.amazon.awscdk.core.StackProps;
import software.amazon.awscdk.services.s3.Bucket;

public class HelloStack extends Stack {
    public HelloStack(final Construct parent, final String id) {
        this(parent, id, null);
    }

    public HelloStack(final Construct parent, final String id, final StackProps props) {
        super(parent, id, props);

        Bucket bucket = new Bucket(this, "MyFirstBucket");
    }
}
and here's what I've got:
(ns hello-cdk.hello-stack
  (:gen-class
   :extends software.amazon.awscdk.core.Stack
   :constructors {[software.amazon.awscdk.core.Construct String]
                  [software.amazon.awscdk.core.Construct String software.amazon.awscdk.core.StackProps]}
   :init init
   :methods [[bucket [String] void]])
  (:import (software.amazon.awscdk.services.s3 Bucket)))

(defn -init
  [parent id] [[parent id nil] nil])

(defn -bucket [this]
  (new Bucket this "MyFirstBucket"))

johnjelinek02:09:28

I can't seem to call (.-bucket (new hello_cdk.hello_stack (new App) "stack"))

johnjelinek02:09:32

how else should I add a bucket to the object that extends from the Stack class? Since it doesn't seem like I can put that stuff in (defn -init constructor definitions

johnjelinek02:09:27

zomg ... I can do this:

(ns 
  (:import (software.amazon.awscdk.core App Stack)
           (software.amazon.awscdk.services.s3 Bucket)))

(defn -main [& argv]
  (let [app (new App)
        stack (new Stack app "hello-cdk")
        bucket (new Bucket stack "sup")]
    (.synth app)))

❤️ 1
johnjelinek02:09:03

I don't even have to build stack classes that extend from stack. I can compose from a stack object

johnjelinek02:09:14

freakin' bananas ... this is awesome

johnjelinek02:09:22

no more aot needed

seancorfield02:09:14

Seems a bit weird that you wrap App in a Stack and then wrap that in a Bucket but still call a method on the App object...

johnjelinek02:09:48

ya, there's a bug upstream where you have to call (.synth app) at the end for it to do stuff

seancorfield02:09:54

I would expect to call a method on the Bucket that is wrapped around everything... How counter-intuitive!

johnjelinek02:09:30

looks like I can compose like this:

(ns 
  (:import (software.amazon.awscdk.core App Stack Construct)
           (software.amazon.awscdk.services.s3 Bucket)
           (software.amazon.awscdk.services.iam User)))

(defn make-bucket [parent id user]
  (let [construct (new Construct parent id)
        bucket (new Bucket construct (str "bucket-" id))]
    (.grantRead bucket user "*")))

(defn -main [& argv]
  (let [app (new App)]
    (doseq [i (map inc (range 3))]
      (let [stack (new Stack app (str "hello-cdk-" i))
            user (new User stack "wat")]
        (doseq [j (map inc (range 1))]
          (make-bucket stack (str "bucket-" j) user))))
    (.synth app)))

johnjelinek03:09:39

pretty freakin' sweet

johnjelinek03:09:32

because that means I don't have to manage yaml that explodes out to this:

Resources:
  watBDB9B42E:
    Type: AWS::IAM::User
    Metadata:
      aws:cdk:path: hello-cdk-1/wat/Resource
  watDefaultPolicy90201DD6:
    Type: AWS::IAM::Policy
    Properties:
      PolicyDocument:
        Statement:
          - Action:
              - s3:GetObject*
              - s3:GetBucket*
              - s3:List*
            Effect: Allow
            Resource:
              - Fn::GetAtt:
                  - bucket1bucketbucket1DE0D1BD6
                  - Arn
              - Fn::Join:
                  - ""
                  - - Fn::GetAtt:
                        - bucket1bucketbucket1DE0D1BD6
                        - Arn
                    - /*
        Version: "2012-10-17"
      PolicyName: watDefaultPolicy90201DD6
      Users:
        - Ref: watBDB9B42E
    Metadata:
      aws:cdk:path: hello-cdk-1/wat/DefaultPolicy/Resource
  bucket1bucketbucket1DE0D1BD6:
    Type: AWS::S3::Bucket
    UpdateReplacePolicy: Retain
    DeletionPolicy: Retain
    Metadata:
      aws:cdk:path: hello-cdk-1/bucket-1/bucket-bucket-1/Resource
  CDKMetadata:
    Type: AWS::CDK::Metadata
    Properties:
      Modules: aws-cdk=1.6.1,@aws-cdk/aws-events=1.6.1,@aws-cdk/aws-iam=1.6.1,@aws-cdk/aws-kms=1.6.1,@aws-cdk/aws-s3=1.6.1,@aws-cdk/core=1.6.1,@aws-cdk/cx-api=1.6.1,@aws-cdk/region-info=1.6.1,jsii-runtime=Java/1.8.0_222

johnjelinek03:09:21

what's particularly interesting is that AWS has only created a typescript library for all this, and their java bindings have an embedded javascript engine to interact with the typescript library -- and I can compose that together like ☝️ from clj

seancorfield03:09:07

Clojure makes Java almost tolerable 🙂

💯 3
johnjelinek03:09:25

new topic: does anyone use deps.edn aliases to run shell commands?

johnjelinek03:09:40

or ... do you just Makefile?

seancorfield03:09:54

@johnjelinek We have a couple of things that we run via aliases that are, ultimately, just shell commands, but most of what our aliases let us run are small Clojure programs rather than shell commands.

👍 1
seancorfield03:09:38

We drive all our clojure commands from a shell script called build -- mostly just so we can run multiple commands easily.

👍 1
seancorfield03:09:43

So build uberjar api run ci-ftp api server will run clojure -A:uberjar in the api subproject and then run clojure -A:ci-ftp server in the api subproject.

seancorfield03:09:06

(there's a bit more to it than that, but that's the essence of it)

prnsml13:09:53

Hi, I started playing with Clojure and now stuck with this... How I could catch what terminal returns after doing (print (str (char 27) "[6n")) ?

Søren Sjørup13:09:41

(with-out-str (print (str (char 27) "[6n"))) => "[6n"

prnsml15:09:54

Not sure if that works for me. After I write (str (char 27) "[6n") in ANSI terminal it returns "Device Status Report" (cursor position) into http://std.in and I want to catch that. Now I found that (flush) could help me:

(do (print (str (char 27) "[6n"))
    (flush)
    (println (read-line)))
But this still it is not catching exactly what I want.

prnsml16:09:21

@manutter51 thanks, so with (sh "/bin/sh" "-c" "stty size </dev/tty") I can get terminal size now. (Or with "tput lines" and "tput cols" to get only height or width). Probably it would be fine for now and I'll come back to this after I learn more about *in* and *out* :D

manutter5116:09:46

There’s also a library that may interest you, depending on what you’re doing: https://github.com/MultiMUD/clojure-lanterna

tjb17:09:25

hey everyone! just posting an update from last Friday when i asked about creating an api server using Clojure. good news! i was able to get some routes working with Ring + Compojure. more to come i hope! i will post updates when i learn new things / migrate more things over from node -> clojure

3
upside_down_parrot 1
parens 1
clj 1
sove19:09:24

how can i make sure the javascript i make only runs on the website it's designed for? can i get info about its runtime env from within the js? i'm making an interactive textbook and i don't want someone to be able to jack the js and run with it

andy.fingerhut19:09:05

I am not sure what you are asking -- are you asking if there is a way to prevent someone from copying the JavaScript code you write and include in a web site? If so, I think fundamentally a web site must give out copies of the JavaScript source code to all users of the site, so that is completely at odds with hiding the JavaScript code from the world. But maybe you are asking a different question than that?

andy.fingerhut19:09:04

If you are looking for ways to protect your intellectual property, then legal mechanisms like copyright, trademark, and licenses are likely your best bet.

Adrian Smith19:09:00

I have a secret that I'd like to pass to my app probably via untracked file, what's the most idomatic way of doing that in Clojure I can see environ, but looks like it supports .lein-env, .boot-env but not .deps.env?

Lennart Buit19:09:57

https://github.com/juxt/aero is also a great config library ^^

sove20:09:15

@andy.fingerhut you make a good point, and perhaps it is the wrong hose for the right fluid, but i was wondering if there is an easy way for me to have my javascript app check the domain name or something. of course, anyone who decompiles it would easily be able to get around such a thing

andy.fingerhut20:09:18

If you make something that is successful enough for people to want to get around such things, you should at that point have enough money to hire good intellectual property attorneys 🙂

sove20:09:19

haha alright, sounds good. well it's a digital version of a textbook, and it has drills so it's got exercises that make it even more useful than an ordinary text

andy.fingerhut20:09:42

They don't even need to decompile -- the JavaScript source code is sent from web servers to the web browser of all site users. You can obfuscate that source code to make it much more difficult to read and understand, but you can't prevent them from seeing it.

sove20:09:45

i'm wondering about how to split it up. maybe just keep all the data on the server and dish it out bit by bit instead of having everything live inside the cljs app

sove20:09:43

Right, right.

andy.fingerhut20:09:08

I'm not experienced in this kind of stuff, but I'm pretty sure many sites require user accounts, and build in 'phone home' at enough places in their JS code that it becomes difficult to do anything effective without the server running.

sove20:09:45

makes sense

dpsutton20:09:48

also, your code will be advanced compiled and quite gnarly to read

harrytuttle22:09:01

Hi, I'm back coding in Clojure after two years and now instead of Leiningen, there's some other thing called Clojure Deps. Is Leiningen dead now? Is Deps the new thing?

hiredman22:09:41

deps is new, lein is not dead, but because deps is new there is a little of buzz and activity around it

hiredman22:09:54

and because tools deps is position itself as not a build tool, there are lein like projects being built around it to manage builds

harrytuttle22:09:22

Yeah, that is confusing. Lein already did build and dependencies. I don't understand what the point of Deps is because of that

hiredman22:09:49

to some degree the idea is that most clojure projects don't need a build step, and can be consumed as just source code

johnj22:09:22

but libraries need to be build as jars or does clojars supports git[hub]?

andy.fingerhut22:09:32

Clojure libraries consisting of only Clojure source code (i.e. no Java source code) can be used via Clojure Deps without ever creating a JAR from them.

johnj22:09:28

I mean, if you need to publish for public consumption

andy.fingerhut22:09:17

If your consumers are using Boot or Leiningen, then yes you must create a JAR for them to use (or they must create one for themselves). If the consumers are using Clojure Deps, they do not need a JAR

hiredman22:09:31

git repos can be public

andy.fingerhut22:09:55

Clojure Deps can use JARs, of course. It just doesn't need them.

johnj22:09:31

got it, shouldhave clarified I was talking more about registries

seancorfield22:09:59

@burnsidemk Also worth pointing out that even with Leiningen going strong, Boot came along as an alternative build tool and is also still going strong. So now you have lein, boot, and clj/`deps.edn`.

andy.fingerhut22:09:37

If one is comfortable with Leiningen's capabilities, and isn't hitting any significant limitations from using it, I wouldn't try to convince you to move away from it.

seancorfield22:09:41

The CLI/`deps.edn` approach can consume JARs on Maven/Clojars/similar and also various Git repos and also local JARs and source projects. lein and boot can't do the latter two "out of the box" although there are probably plugins available to do some of that(?). There are also plugins for lein and boot that leverage the new deps.edn machinery (although that can be problematic because the deps.edn machinery has a deliberately different algorithm for resolving "conflicting" dependency versions -- one that is more intuitive and should provide fewer "surprises").

seancorfield22:09:52

I agree with @andy.fingerhut -- if you're using lein and you're happy with it, keep using it. If you're using boot and you're happy with it, keep using it. If you're coming to Clojure fresh, or just curious about how the landscape has changed, check out the new CLI/`deps.edn` stuff.

johnj22:09:47

yeah, but if you want to be in clojars or maven central you need a build a step

seancorfield22:09:12

(FWIW, at World Singles Networks, we started with lein back in 2011 because that's all there was, switched to boot in 2015 to make it easier to manage our monorepo, and switched to CLI/`deps.edn` in 2018 because we'd already started to store our dependencies in EDN files with boot...)

seancorfield22:09:56

@lockdown- I deploy almost all of my projects to Clojars using CLI/`deps.edn` and depstar -- and we use depstar at work to build all our uberjars for production deployment.

andy.fingerhut22:09:16

I believe that most JARs on Clojars contain only Clojure source code, no compiled .class files, and there are commands to create such source-only JARs for deployment from deps.edn projects, one of which Sean just mentioned 🙂

seancorfield22:09:26

https://github.com/clojure/tools.deps.alpha/wiki/Tools -- all sorts of CLI/`deps.edn` tools are available.

johnj23:09:14

nice, thanks

seancorfield23:09:37

(we manage almost 90K lines of Clojure at work with CLI/`deps.edn` and a small shell script -- that really just automates running multiple clojure commands one after the other)

johnj23:09:31

is that a single codebase?

seancorfield23:09:14

Yes, a monorepository with about 30 or so subprojects.

seancorfield23:09:46

That's all of our backend code (mostly APIs but also a few server-side rendered apps)

Darrell23:09:05

I have a test file that when I run it is failing on a test that I have commented out. Is there something I need to do to get it to ignore the commented out test?

hiredman23:09:25

how are you running it?

noisesmith23:09:02

if you make an empty defn with the same name as the test, that can reset the test state in the repl

noisesmith23:09:09

or you can unmap the var from the ns

Darrell23:09:18

I’m a Vim user with Fireplace so I’m just running :.RunTests

hiredman23:09:25

my guess is you are not running the "test file" but running the tests in the a repl so running the tests defined in a namespace in memory

hiredman23:09:04

the test exists in memory and you need to delete it from memory, or overwrite it

hiredman23:09:29

(def test-name nil) then reloading the file would be one way

hiredman23:09:55

(ns-unmap 'test-ns 'test-name) would be another

Darrell23:09:19

I’ll give that a try. Thanks!

hiredman23:09:04

maybe even easier would be to comment out the body of the test, and not the whole test leaving something like (deftest test-name (comment whatever) )

Darrell23:09:18

@hiredman That last one worked perfectly. Thanks again!