diff --git a/compiled_starters/elixir/.codecrafters/compile.sh b/compiled_starters/elixir/.codecrafters/compile.sh new file mode 100755 index 0000000..a8b6ada --- /dev/null +++ b/compiled_starters/elixir/.codecrafters/compile.sh @@ -0,0 +1,11 @@ +#!/bin/sh +# +# This script is used to compile your program on CodeCrafters +# +# This runs before .codecrafters/run.sh +# +# Learn more: https://codecrafters.io/program-interface + +set -e # Exit on failure + +# (This file is empty since Elixir programs don't use a compile step) diff --git a/compiled_starters/elixir/.codecrafters/run.sh b/compiled_starters/elixir/.codecrafters/run.sh new file mode 100755 index 0000000..26c5818 --- /dev/null +++ b/compiled_starters/elixir/.codecrafters/run.sh @@ -0,0 +1,11 @@ +#!/bin/sh +# +# This script is used to run your program on CodeCrafters +# +# This runs after .codecrafters/compile.sh +# +# Learn more: https://codecrafters.io/program-interface + +set -e # Exit on failure + +exec mix run --no-halt -- "$@" diff --git a/compiled_starters/elixir/.formatter.exs b/compiled_starters/elixir/.formatter.exs new file mode 100644 index 0000000..d2cda26 --- /dev/null +++ b/compiled_starters/elixir/.formatter.exs @@ -0,0 +1,4 @@ +# Used by "mix format" +[ + inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] +] diff --git a/compiled_starters/elixir/.gitattributes b/compiled_starters/elixir/.gitattributes new file mode 100644 index 0000000..176a458 --- /dev/null +++ b/compiled_starters/elixir/.gitattributes @@ -0,0 +1 @@ +* text=auto diff --git a/compiled_starters/elixir/.gitignore b/compiled_starters/elixir/.gitignore new file mode 100644 index 0000000..39fc292 --- /dev/null +++ b/compiled_starters/elixir/.gitignore @@ -0,0 +1,24 @@ +# The directory Mix will write compiled artifacts to. +/_build/ + +# If you run "mix test --cover", coverage assets end up here. +/cover/ + +# The directory Mix downloads your dependencies sources to. +/deps/ + +# Where third-party dependencies like ExDoc output generated docs. +/doc/ + +# Ignore .fetch files in case you like to edit your project deps locally. +/.fetch + +# If the VM crashes, it generates a dump, let's ignore it too. +erl_crash.dump + +# Also ignore archive artifacts (built via "mix archive.build"). +*.ez + +# Ignore package tarball (built via "mix hex.build"). +app-*.tar + diff --git a/compiled_starters/elixir/README.md b/compiled_starters/elixir/README.md new file mode 100644 index 0000000..1018733 --- /dev/null +++ b/compiled_starters/elixir/README.md @@ -0,0 +1,34 @@ +![progress-banner](https://codecrafters.io/landing/images/default_progress_banners/kafka.png) + +This is a starting point for Elixir solutions to the +["Build Your Own Kafka" Challenge](https://codecrafters.io/challenges/kafka). + +In this challenge, you'll build a toy Kafka clone that's capable of accepting +and responding to APIVersions & Fetch API requests. You'll also learn about +encoding and decoding messages using the Kafka wire protocol. You'll also learn +about handling the network protocol, event loops, TCP sockets and more. + +**Note**: If you're viewing this repo on GitHub, head over to +[codecrafters.io](https://codecrafters.io) to try the challenge. + +# Passing the first stage + +The entry point for your Kafka implementation is in `lib/server.ex`. Study and +uncomment the relevant code, and push your changes to pass the first stage: + +```sh +git commit -am "pass 1st stage" # any msg +git push origin master +``` + +That's all! + +# Stage 2 & beyond + +Note: This section is for stages 2 and beyond. + +1. Ensure you have `mix` installed locally +1. Run `./your_program.sh` to run your Kafka broker, which is implemented in + `lib/server.ex`. +1. Commit your changes and run `git push origin master` to submit your solution + to CodeCrafters. Test output will be streamed to your terminal. diff --git a/compiled_starters/elixir/codecrafters.yml b/compiled_starters/elixir/codecrafters.yml new file mode 100644 index 0000000..eaed767 --- /dev/null +++ b/compiled_starters/elixir/codecrafters.yml @@ -0,0 +1,11 @@ +# Set this to true if you want debug logs. +# +# These can be VERY verbose, so we suggest turning them off +# unless you really need them. +debug: false + +# Use this to change the Elixir version used to run your code +# on Codecrafters. +# +# Available versions: elixir-1.17 +language_pack: elixir-1.17 diff --git a/compiled_starters/elixir/lib/server.ex b/compiled_starters/elixir/lib/server.ex new file mode 100644 index 0000000..283ce10 --- /dev/null +++ b/compiled_starters/elixir/lib/server.ex @@ -0,0 +1,26 @@ +defmodule Server do + @moduledoc """ + Your implementation of a Kafka broker + """ + + use Application + + def start(_type, _args) do + Supervisor.start_link([{Task, fn -> Server.listen() end}], strategy: :one_for_one) + end + + @doc """ + Listen for incoming connections + """ + def listen() do + # You can use print statements as follows for debugging, they'll be visible when running tests. + IO.puts("Logs from your program will appear here!") + + # Uncomment this block to pass the first stage + # + # # Since the tester restarts your program quite often, setting SO_REUSEADDR + # # ensures that we don't run into 'Address already in use' errors + # {:ok, socket} = :gen_tcp.listen(9092, [:binary, active: false, reuseaddr: true]) + # {:ok, _client} = :gen_tcp.accept(socket) + end +end diff --git a/compiled_starters/elixir/mix.exs b/compiled_starters/elixir/mix.exs new file mode 100644 index 0000000..78d57ea --- /dev/null +++ b/compiled_starters/elixir/mix.exs @@ -0,0 +1,20 @@ +defmodule App.MixProject do + # NOTE: You do not need to change anything in this file. + use Mix.Project + + def project do + [ + app: :kafka, + version: "1.0.0", + elixir: "~> 1.10", + start_permanent: Mix.env() == :prod + ] + end + + def application do + [ + extra_applications: [:logger], + mod: {Server, []} + ] + end +end diff --git a/compiled_starters/elixir/your_program.sh b/compiled_starters/elixir/your_program.sh new file mode 100755 index 0000000..17642bc --- /dev/null +++ b/compiled_starters/elixir/your_program.sh @@ -0,0 +1,15 @@ +#!/bin/sh +# +# Use this script to run your program LOCALLY. +# +# Note: Changing this script WILL NOT affect how CodeCrafters runs your program. +# +# Learn more: https://codecrafters.io/program-interface + +set -e # Exit early if any commands fail + +# Copied from .codecrafters/run.sh +# +# - Edit this to change how your program runs locally +# - Edit .codecrafters/run.sh to change how your program runs remotely +exec mix run --no-halt -- "$@" diff --git a/course-definition.yml b/course-definition.yml index 008b91d..64e9bc4 100644 --- a/course-definition.yml +++ b/course-definition.yml @@ -21,6 +21,9 @@ languages: - slug: "javascript" - slug: "python" - slug: "rust" + - slug: "elixir" + release_status: "alpha" + alpha_tester_usernames: ["hlorellium"] marketing: difficulty: medium diff --git a/dockerfiles/elixir-1.17.Dockerfile b/dockerfiles/elixir-1.17.Dockerfile new file mode 100644 index 0000000..e424f78 --- /dev/null +++ b/dockerfiles/elixir-1.17.Dockerfile @@ -0,0 +1,17 @@ +# syntax=docker/dockerfile:1.7-labs +FROM elixir:1.17.2-alpine + +# Ensures the container is re-built if dependency files change +ENV CODECRAFTERS_DEPENDENCY_FILE_PATHS="mix.exs" + +WORKDIR /app + +# .git & README.md are unique per-repository. We ignore them on first copy to prevent cache misses +COPY --exclude=.git --exclude=README.md . /app + +# Install & cache deps +RUN .codecrafters/compile.sh + +# If _build directory exists, move it to /app-cached +RUN mkdir -p /app-cached +RUN if [ -d "/app/_build" ]; then mv /app/_build /app-cached; fi diff --git a/solutions/elixir/01-vi6/code/.codecrafters/compile.sh b/solutions/elixir/01-vi6/code/.codecrafters/compile.sh new file mode 100755 index 0000000..a8b6ada --- /dev/null +++ b/solutions/elixir/01-vi6/code/.codecrafters/compile.sh @@ -0,0 +1,11 @@ +#!/bin/sh +# +# This script is used to compile your program on CodeCrafters +# +# This runs before .codecrafters/run.sh +# +# Learn more: https://codecrafters.io/program-interface + +set -e # Exit on failure + +# (This file is empty since Elixir programs don't use a compile step) diff --git a/solutions/elixir/01-vi6/code/.codecrafters/run.sh b/solutions/elixir/01-vi6/code/.codecrafters/run.sh new file mode 100755 index 0000000..26c5818 --- /dev/null +++ b/solutions/elixir/01-vi6/code/.codecrafters/run.sh @@ -0,0 +1,11 @@ +#!/bin/sh +# +# This script is used to run your program on CodeCrafters +# +# This runs after .codecrafters/compile.sh +# +# Learn more: https://codecrafters.io/program-interface + +set -e # Exit on failure + +exec mix run --no-halt -- "$@" diff --git a/solutions/elixir/01-vi6/code/.formatter.exs b/solutions/elixir/01-vi6/code/.formatter.exs new file mode 100644 index 0000000..d2cda26 --- /dev/null +++ b/solutions/elixir/01-vi6/code/.formatter.exs @@ -0,0 +1,4 @@ +# Used by "mix format" +[ + inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] +] diff --git a/solutions/elixir/01-vi6/code/.gitattributes b/solutions/elixir/01-vi6/code/.gitattributes new file mode 100644 index 0000000..176a458 --- /dev/null +++ b/solutions/elixir/01-vi6/code/.gitattributes @@ -0,0 +1 @@ +* text=auto diff --git a/solutions/elixir/01-vi6/code/.gitignore b/solutions/elixir/01-vi6/code/.gitignore new file mode 100644 index 0000000..39fc292 --- /dev/null +++ b/solutions/elixir/01-vi6/code/.gitignore @@ -0,0 +1,24 @@ +# The directory Mix will write compiled artifacts to. +/_build/ + +# If you run "mix test --cover", coverage assets end up here. +/cover/ + +# The directory Mix downloads your dependencies sources to. +/deps/ + +# Where third-party dependencies like ExDoc output generated docs. +/doc/ + +# Ignore .fetch files in case you like to edit your project deps locally. +/.fetch + +# If the VM crashes, it generates a dump, let's ignore it too. +erl_crash.dump + +# Also ignore archive artifacts (built via "mix archive.build"). +*.ez + +# Ignore package tarball (built via "mix hex.build"). +app-*.tar + diff --git a/solutions/elixir/01-vi6/code/README.md b/solutions/elixir/01-vi6/code/README.md new file mode 100644 index 0000000..1018733 --- /dev/null +++ b/solutions/elixir/01-vi6/code/README.md @@ -0,0 +1,34 @@ +![progress-banner](https://codecrafters.io/landing/images/default_progress_banners/kafka.png) + +This is a starting point for Elixir solutions to the +["Build Your Own Kafka" Challenge](https://codecrafters.io/challenges/kafka). + +In this challenge, you'll build a toy Kafka clone that's capable of accepting +and responding to APIVersions & Fetch API requests. You'll also learn about +encoding and decoding messages using the Kafka wire protocol. You'll also learn +about handling the network protocol, event loops, TCP sockets and more. + +**Note**: If you're viewing this repo on GitHub, head over to +[codecrafters.io](https://codecrafters.io) to try the challenge. + +# Passing the first stage + +The entry point for your Kafka implementation is in `lib/server.ex`. Study and +uncomment the relevant code, and push your changes to pass the first stage: + +```sh +git commit -am "pass 1st stage" # any msg +git push origin master +``` + +That's all! + +# Stage 2 & beyond + +Note: This section is for stages 2 and beyond. + +1. Ensure you have `mix` installed locally +1. Run `./your_program.sh` to run your Kafka broker, which is implemented in + `lib/server.ex`. +1. Commit your changes and run `git push origin master` to submit your solution + to CodeCrafters. Test output will be streamed to your terminal. diff --git a/solutions/elixir/01-vi6/code/codecrafters.yml b/solutions/elixir/01-vi6/code/codecrafters.yml new file mode 100644 index 0000000..eaed767 --- /dev/null +++ b/solutions/elixir/01-vi6/code/codecrafters.yml @@ -0,0 +1,11 @@ +# Set this to true if you want debug logs. +# +# These can be VERY verbose, so we suggest turning them off +# unless you really need them. +debug: false + +# Use this to change the Elixir version used to run your code +# on Codecrafters. +# +# Available versions: elixir-1.17 +language_pack: elixir-1.17 diff --git a/solutions/elixir/01-vi6/code/lib/server.ex b/solutions/elixir/01-vi6/code/lib/server.ex new file mode 100644 index 0000000..e980e9a --- /dev/null +++ b/solutions/elixir/01-vi6/code/lib/server.ex @@ -0,0 +1,21 @@ +defmodule Server do + @moduledoc """ + Your implementation of a Kafka broker + """ + + use Application + + def start(_type, _args) do + Supervisor.start_link([{Task, fn -> Server.listen() end}], strategy: :one_for_one) + end + + @doc """ + Listen for incoming connections + """ + def listen() do + # Since the tester restarts your program quite often, setting SO_REUSEADDR + # ensures that we don't run into 'Address already in use' errors + {:ok, socket} = :gen_tcp.listen(9092, [:binary, active: false, reuseaddr: true]) + {:ok, _client} = :gen_tcp.accept(socket) + end +end diff --git a/solutions/elixir/01-vi6/code/mix.exs b/solutions/elixir/01-vi6/code/mix.exs new file mode 100644 index 0000000..78d57ea --- /dev/null +++ b/solutions/elixir/01-vi6/code/mix.exs @@ -0,0 +1,20 @@ +defmodule App.MixProject do + # NOTE: You do not need to change anything in this file. + use Mix.Project + + def project do + [ + app: :kafka, + version: "1.0.0", + elixir: "~> 1.10", + start_permanent: Mix.env() == :prod + ] + end + + def application do + [ + extra_applications: [:logger], + mod: {Server, []} + ] + end +end diff --git a/solutions/elixir/01-vi6/code/your_program.sh b/solutions/elixir/01-vi6/code/your_program.sh new file mode 100755 index 0000000..17642bc --- /dev/null +++ b/solutions/elixir/01-vi6/code/your_program.sh @@ -0,0 +1,15 @@ +#!/bin/sh +# +# Use this script to run your program LOCALLY. +# +# Note: Changing this script WILL NOT affect how CodeCrafters runs your program. +# +# Learn more: https://codecrafters.io/program-interface + +set -e # Exit early if any commands fail + +# Copied from .codecrafters/run.sh +# +# - Edit this to change how your program runs locally +# - Edit .codecrafters/run.sh to change how your program runs remotely +exec mix run --no-halt -- "$@" diff --git a/solutions/elixir/01-vi6/diff/lib/server.ex.diff b/solutions/elixir/01-vi6/diff/lib/server.ex.diff new file mode 100644 index 0000000..f97a351 --- /dev/null +++ b/solutions/elixir/01-vi6/diff/lib/server.ex.diff @@ -0,0 +1,31 @@ +@@ -1,26 +1,21 @@ + defmodule Server do + @moduledoc """ + Your implementation of a Kafka broker + """ + + use Application + + def start(_type, _args) do + Supervisor.start_link([{Task, fn -> Server.listen() end}], strategy: :one_for_one) + end + + @doc """ + Listen for incoming connections + """ + def listen() do +- # You can use print statements as follows for debugging, they'll be visible when running tests. +- IO.puts("Logs from your program will appear here!") +- +- # Uncomment this block to pass the first stage +- # +- # # Since the tester restarts your program quite often, setting SO_REUSEADDR +- # # ensures that we don't run into 'Address already in use' errors +- # {:ok, socket} = :gen_tcp.listen(9092, [:binary, active: false, reuseaddr: true]) +- # {:ok, _client} = :gen_tcp.accept(socket) ++ # Since the tester restarts your program quite often, setting SO_REUSEADDR ++ # ensures that we don't run into 'Address already in use' errors ++ {:ok, socket} = :gen_tcp.listen(9092, [:binary, active: false, reuseaddr: true]) ++ {:ok, _client} = :gen_tcp.accept(socket) + end + end diff --git a/solutions/elixir/01-vi6/explanation.md b/solutions/elixir/01-vi6/explanation.md new file mode 100644 index 0000000..19b8440 --- /dev/null +++ b/solutions/elixir/01-vi6/explanation.md @@ -0,0 +1,20 @@ +The entry point for your Kafka implementation is in `lib/server.ex`. + +Study and uncomment the relevant code: + +```elixir +# Uncomment this block to pass the first stage + +# Since the tester restarts your program quite often, setting SO_REUSEADDR +# ensures that we don't run into 'Address already in use' errors +{:ok, socket} = :gen_tcp.listen(9092, [:binary, active: false, reuseaddr: true]) +{:ok, _client} = :gen_tcp.accept(socket) +``` + +Push your changes to pass the first stage: + +``` +git add . +git commit -m "pass 1st stage" # any msg +git push origin master +``` diff --git a/starter_templates/elixir/code/.codecrafters/compile.sh b/starter_templates/elixir/code/.codecrafters/compile.sh new file mode 100755 index 0000000..a8b6ada --- /dev/null +++ b/starter_templates/elixir/code/.codecrafters/compile.sh @@ -0,0 +1,11 @@ +#!/bin/sh +# +# This script is used to compile your program on CodeCrafters +# +# This runs before .codecrafters/run.sh +# +# Learn more: https://codecrafters.io/program-interface + +set -e # Exit on failure + +# (This file is empty since Elixir programs don't use a compile step) diff --git a/starter_templates/elixir/code/.codecrafters/run.sh b/starter_templates/elixir/code/.codecrafters/run.sh new file mode 100755 index 0000000..26c5818 --- /dev/null +++ b/starter_templates/elixir/code/.codecrafters/run.sh @@ -0,0 +1,11 @@ +#!/bin/sh +# +# This script is used to run your program on CodeCrafters +# +# This runs after .codecrafters/compile.sh +# +# Learn more: https://codecrafters.io/program-interface + +set -e # Exit on failure + +exec mix run --no-halt -- "$@" diff --git a/starter_templates/elixir/code/.formatter.exs b/starter_templates/elixir/code/.formatter.exs new file mode 100644 index 0000000..d2cda26 --- /dev/null +++ b/starter_templates/elixir/code/.formatter.exs @@ -0,0 +1,4 @@ +# Used by "mix format" +[ + inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] +] diff --git a/starter_templates/elixir/code/.gitignore b/starter_templates/elixir/code/.gitignore new file mode 100644 index 0000000..39fc292 --- /dev/null +++ b/starter_templates/elixir/code/.gitignore @@ -0,0 +1,24 @@ +# The directory Mix will write compiled artifacts to. +/_build/ + +# If you run "mix test --cover", coverage assets end up here. +/cover/ + +# The directory Mix downloads your dependencies sources to. +/deps/ + +# Where third-party dependencies like ExDoc output generated docs. +/doc/ + +# Ignore .fetch files in case you like to edit your project deps locally. +/.fetch + +# If the VM crashes, it generates a dump, let's ignore it too. +erl_crash.dump + +# Also ignore archive artifacts (built via "mix archive.build"). +*.ez + +# Ignore package tarball (built via "mix hex.build"). +app-*.tar + diff --git a/starter_templates/elixir/code/lib/server.ex b/starter_templates/elixir/code/lib/server.ex new file mode 100644 index 0000000..283ce10 --- /dev/null +++ b/starter_templates/elixir/code/lib/server.ex @@ -0,0 +1,26 @@ +defmodule Server do + @moduledoc """ + Your implementation of a Kafka broker + """ + + use Application + + def start(_type, _args) do + Supervisor.start_link([{Task, fn -> Server.listen() end}], strategy: :one_for_one) + end + + @doc """ + Listen for incoming connections + """ + def listen() do + # You can use print statements as follows for debugging, they'll be visible when running tests. + IO.puts("Logs from your program will appear here!") + + # Uncomment this block to pass the first stage + # + # # Since the tester restarts your program quite often, setting SO_REUSEADDR + # # ensures that we don't run into 'Address already in use' errors + # {:ok, socket} = :gen_tcp.listen(9092, [:binary, active: false, reuseaddr: true]) + # {:ok, _client} = :gen_tcp.accept(socket) + end +end diff --git a/starter_templates/elixir/code/mix.exs b/starter_templates/elixir/code/mix.exs new file mode 100644 index 0000000..78d57ea --- /dev/null +++ b/starter_templates/elixir/code/mix.exs @@ -0,0 +1,20 @@ +defmodule App.MixProject do + # NOTE: You do not need to change anything in this file. + use Mix.Project + + def project do + [ + app: :kafka, + version: "1.0.0", + elixir: "~> 1.10", + start_permanent: Mix.env() == :prod + ] + end + + def application do + [ + extra_applications: [:logger], + mod: {Server, []} + ] + end +end diff --git a/starter_templates/elixir/config.yml b/starter_templates/elixir/config.yml new file mode 100644 index 0000000..58e8ddc --- /dev/null +++ b/starter_templates/elixir/config.yml @@ -0,0 +1,3 @@ +attributes: + required_executable: mix + user_editable_file: lib/server.ex