profile
viewpoint
Eric Meadows-Jönsson ericmj Gothenburg, Sweden https://ericmj.github.io/ @elixir-lang core team member and creator of the @hexpm package manager

elixir-plug/plug 2450

A specification and conveniences for composable modules between web applications

elixir-mint/mint 1094

Functional HTTP client for Elixir with support for HTTP/1 and HTTP/2.

elixir-ecto/postgrex 876

PostgreSQL driver for Elixir

elixir-protobuf/protobuf 564

A pure Elixir implementation of Google Protobuf.

elixir-mongo/mongodb 502

MongoDB driver for Elixir

ericmj/decimal 371

Arbitrary precision decimal arithmetic

elixir-mongo/mongodb_ecto 325

MongoDB adapter for Ecto

elixir-ecto/db_connection 247

Database connection behaviour

batate/blacksmith 170

Data generation framework for Elixir

batate/shouldi 135

Elixir testing libraries with nested contexts, superior readability, and ease of use

Pull request review commenthexpm/hex

Add support for reading credentials from .netrc files

+defmodule Hex.Netrc do+  @moduledoc false++  def lookup(host, path \\ netrc_path()) when is_binary(host) and is_binary(path) do+    with {:ok, %{} = machines} <- parse(path) do+      Map.get(machines, host)+    end+  end++  def parse(path \\ netrc_path()) when is_binary(path) do+    with {:ok, contents} <- File.read(path) do+      parse_contents(contents)+    end+  end++  defp parse_contents(contents) when is_binary(contents) do

Yeah, that would work 👍

frerich

comment created time in an hour

PullRequestReviewEvent

Pull request review commenthexpm/hexpm

style create password page

     "postcss-import": "^14.0.2",     "postcss-loader": "^4.2.0",     "tailwindcss": "^2.2.19"+  },+  "dependencies": {+    "@tailwindcss/forms": "^0.3.4"

Should this be in devDependencies instead?

TraceyOnim

comment created time in an hour

PullRequestReviewEvent
PullRequestReviewEvent

Pull request review commenthexpm/hex

Add support for reading credentials from .netrc files

+defmodule Hex.Netrc do+  @moduledoc false++  def lookup(host, path \\ netrc_path()) when is_binary(host) and is_binary(path) do+    with {:ok, %{} = machines} <- parse(path) do+      Map.get(machines, host)+    end+  end++  def parse(path \\ netrc_path()) when is_binary(path) do+    with {:ok, contents} <- File.read(path) do+      parse_contents(contents)+    end+  end++  defp parse_contents(contents) when is_binary(contents) do

Reading at startup isn't great either because in many cases we wont be be doing HTTP requests.

frerich

comment created time in 4 hours

PullRequestReviewEvent

Pull request review commenthexpm/hex

Add support for reading credentials from .netrc files

+defmodule Hex.Netrc do+  @moduledoc false++  def lookup(host, path \\ netrc_path()) when is_binary(host) and is_binary(path) do+    with {:ok, %{} = machines} <- parse(path) do+      Map.get(machines, host)+    end+  end++  def parse(path \\ netrc_path()) when is_binary(path) do+    with {:ok, contents} <- File.read(path) do+      parse_contents(contents)+    end+  end++  defp parse_contents(contents) when is_binary(contents) do

I suspect the operating system is going to cache repeated reads of the file anyway, i.e. all but the first accesses are going to the cache.

That's probably true in many cases but in my experience it is hard to rely on this on machines with varying operating systems and settings.

The file is typically rather small (a couple hundred bytes) and the parsing logic is straightforward -- I don't expect a lot of CPU cycles to be burnt on reading the file.

I am more concerned about the disk IO. Some projects may have up to 100 dependencies which means we would be trying to read this file 200 times even if all packages were cached on disk.

Caching invalidation is hard to get right.

In this case it is easy because hex is always called from a short lived mix task so we don't have to invalidate. I think the tricky part is preventing the N first concurrent requests to not read the file in parallel when the cache is empty in the beginning.

Let's wait with the caching for now, I will think about if there is an easy way of implementing it.

frerich

comment created time in 8 hours

PullRequestReviewEvent

Pull request review commenthexpm/hexpm

WebAuth Proof of Concept

 defmodule Hexpm.Accounts.WebAuthRequest do      audit = {user, request.audit} -    scope = request.scope-    device_code = request.device_code-    name = "Web Auth #{device_code} key"+    key_name = request.key_name -    key_params = %{@key_params | name: name}-    key_params = %{key_params | permissions: [%{@key_permission | resource: scope}]}+    key_params = %{@key_params | name: key_name}++    write_key = %{key_params | permissions: [%{@key_permission | resource: "write"}]}+    read_key = %{key_params | permissions: [%{@key_permission | resource: "read"}]}

What do you think about letting the user specifying what keys and with what permissions to generate? That way it's more flexible for the future.

Benjamin-Philip

comment created time in 8 hours

PullRequestReviewEvent

pull request commenthexpm/hexpm

Live suggestions for homepage package search

If using a small liveview component in a larger page means that the whole page needs to be changed, like here: https://github.com/hexpm/hexpm/pull/1080/files#diff-ae87547521f78e46f7a0c59f22cc2715f4af4e0b6fc213c3b68b45a08b6456c5R58 and here: https://github.com/hexpm/hexpm/pull/1080/files#diff-ae87547521f78e46f7a0c59f22cc2715f4af4e0b6fc213c3b68b45a08b6456c5R132. Along with replacing the controller action with a liveview this does not seem feasible or maintainable.

When looking at the data sent over the websocket after the page load it looks like almost the entire page is sent over the websocket again. I don't understand how render time and CPU usage can be unaffected when it's doing this?

DaniruKun

comment created time in 19 hours

pull request commenthexpm/hexpm

Live suggestions for homepage package search

To answer point 1. - technically we can, but it's now considered the "old" syntax that will be deprecated at some point in favour of the HEEx way of doing things, and I think the .heex extension makes it very clear where it can be used.

Ah yes, we should use the HEEx syntax 👍 .

what do you mean?

Isn't it possible to make section of the page a liveview instead of making the whole page a liveview?

DaniruKun

comment created time in 21 hours

Pull request review commenthexpm/hex

Add support for reading credentials from .netrc files

+defmodule Hex.Netrc do+  @moduledoc false++  def lookup(host, path \\ netrc_path()) when is_binary(host) and is_binary(path) do+    with {:ok, %{} = machines} <- parse(path) do+      Map.get(machines, host)+    end+  end++  def parse(path \\ netrc_path()) when is_binary(path) do+    with {:ok, contents} <- File.read(path) do+      parse_contents(contents)+    end+  end++  defp parse_contents(contents) when is_binary(contents) do+    parse_result =+      contents+      |> String.trim()+      |> String.split("\n", trim: true)+      |> Enum.map(&String.split/1)+      |> Enum.reduce({%{}, nil}, &parse_line/2)
    parse_result =
      contents
      |> String.split("\n", trim: true)
      |> Enum.map(&String.split(&1, trim: true))
      |> Enum.reduce({%{}, nil}, &parse_line/2)
frerich

comment created time in a day

Pull request review commenthexpm/hex

Add support for reading credentials from .netrc files

+defmodule Hex.Netrc do+  @moduledoc false++  def lookup(host, path \\ netrc_path()) when is_binary(host) and is_binary(path) do+    with {:ok, %{} = machines} <- parse(path) do+      Map.get(machines, host)+    end+  end++  def parse(path \\ netrc_path()) when is_binary(path) do+    with {:ok, contents} <- File.read(path) do+      parse_contents(contents)+    end+  end++  defp parse_contents(contents) when is_binary(contents) do

We need to cache the result of the parsing to avoid reading the file on every HTTP request.

frerich

comment created time in a day

PullRequestReviewEvent
PullRequestReviewEvent
PullRequestReviewEvent

pull request commenthexpm/hexpm

Live suggestions for homepage package search

There seems to be a mix of EEx and {} syntax used for interpolation. Can we use only <%= %> syntax?

We don't want to make the whole front page a live view because it's resource intensive and a popular page. Can you make only the search component a live view instead?

DaniruKun

comment created time in a day

Pull request review commenthexpm/hexpm

style create password page

 module.exports = {   variants: {     extend: {}   },-  plugins: []+  plugins: [+  require('@tailwindcss/custom-forms')
    require('@tailwindcss/custom-forms')
TraceyOnim

comment created time in a day

Pull request review commenthexpm/hexpm

style create password page

 {   "license": "Apache-2.0",   "devDependencies": {+    "@tailwindcss/custom-forms": "^0.2.1",

This package is deprecated in favor of @tailwindcss/forms. See https://github.com/tailwindlabs/tailwindcss-custom-forms#readme.

TraceyOnim

comment created time in a day

PullRequestReviewEvent
PullRequestReviewEvent

issue commenthexpm/hex

mix hex.package fetch: Add support for .netrc files

I believe a simple approach which would address all use cases might be to augment Hex.HTTP such that when performing requests, it checks the headers for an optional authorization key. If there is none, it checks a .netrc file to see if the URL to which the request is sent has login credentials defined. If so, an authorization header is constructed on the fly.

I agree.

Should the usage of credentials stored in .netrc be optional?

Yes, it should be optional, having a .netrc file in your home directory should not be required. Maybe I misunderstood your question?

In case .netrc is optional -- is it opt-in (i.e. it's not used by default) or opt-out? I'd personally prefer the latter.

I don't think opt-in or opt-out is necessary, it should be used by default and if someone wants an opt-out we can add it when it's requested.

In case .netrc is optional -- how could this be configured? An environment variable? A new configuration key in hex.config? Something else?

Other tools seems to honor the NETRC environment variable for specifying a path other than the home directory.

frerich

comment created time in a day

Pull request review commentelixir-mint/mint

Handle settings after initial handshake

 defmodule Mint.HTTP2 do    # SETTINGS -  defp handle_settings(conn, frame, responses) do+  defp handle_settings(+         %Mint.HTTP2{enable_async_settings: enable_async_settings} = conn,+         frame,+         responses+       ) do     settings(flags: flags, params: params) = frame      if flag_set?(flags, :settings, :ack) do       {{:value, params}, conn} = get_and_update_in(conn.client_settings_queue, &:queue.out/1)       conn = apply_client_settings(conn, params)-      {conn, responses}++      if enable_async_settings do+        {conn, [:settings_ack | responses]}

Yeah, I don't think we need neither :settings nor :settings_ack for now.

lukebakken

comment created time in a day

PullRequestReviewEvent

Pull request review commentelixir-mint/mint

Handle settings after initial handshake

 defmodule Mint.HTTP2 do    # SETTINGS -  defp handle_settings(conn, frame, responses) do+  defp handle_settings(+         %Mint.HTTP2{enable_async_settings: enable_async_settings} = conn,+         frame,+         responses+       ) do     settings(flags: flags, params: params) = frame      if flag_set?(flags, :settings, :ack) do       {{:value, params}, conn} = get_and_update_in(conn.client_settings_queue, &:queue.out/1)       conn = apply_client_settings(conn, params)-      {conn, responses}++      if enable_async_settings do+        {conn, [:settings_ack | responses]}

I can't really think of a use case for this so unless you have one in mind let's hold on with adding this.

lukebakken

comment created time in a day

Pull request review commentelixir-mint/mint

Handle settings after initial handshake

 defmodule Mint.HTTP2 do    # SETTINGS -  defp handle_settings(conn, frame, responses) do+  defp handle_settings(+         %Mint.HTTP2{enable_async_settings: enable_async_settings} = conn,+         frame,+         responses+       ) do     settings(flags: flags, params: params) = frame      if flag_set?(flags, :settings, :ack) do       {{:value, params}, conn} = get_and_update_in(conn.client_settings_queue, &:queue.out/1)       conn = apply_client_settings(conn, params)-      {conn, responses}++      if enable_async_settings do+        {conn, [:settings_ack | responses]}+      else+        {conn, responses}+      end     else       conn = apply_server_settings(conn, params)       frame = settings(flags: set_flags(:settings, [:ack]), params: [])       conn = send!(conn, Frame.encode(frame))-      {conn, responses}++      if enable_async_settings do+        {conn, [:settings | responses]}

I talked with @whatyouhide and we think this response is not necessary. Sorry for leading you on the wrong path on this. We can return the default settings (called initial value in the spec https://httpwg.org/specs/rfc7540.html#SettingValues) or :unknown from get_server_setting/2 until we have received the first SETTING frame.

lukebakken

comment created time in a day

PullRequestReviewEvent
PullRequestReviewEvent
more