@ethicdevs/crystal-docker-api | Show object: 62f0c572ed0554fd724574e071aa66480e1c5db5 ∙ GitFOSS
62f0c575/14/2026, 9:47:06 AM
feat: initial commit with changes
+ 18
- 225
updated code that was 5 years old so it works again

@@ -1,6 +1,6 @@
 The MIT License (MIT)
 
-Copyright (c) 2020 EthicDevs & Place Technology Limited
+Copyright (c) 2020 Place Technology Limited
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal

@@ -15,8 +15,7 @@ Client structure has been designed to mirror API provided by the [official pytho
    ```yaml
    dependencies:
      docker:
-       git: https://gitfoss.dev/ethicdevs/crystal-docker-api.git
-       branch: master
+       github: aca-labs/crystal-docker
    ```
 
 2. Run `shards install`

...
@@ -35,6 +34,5 @@ Read [the docs](https://aca-labs.github.io/crystal-docker/).
 
 ## Contributors
 
-- [Willi Wonka](https://gitfoss.dev/willi.wonka38) - maintainer
-- [Kim Burgess](https://github.com/kimburgess) - creator
+- [Kim Burgess](https://github.com/kimburgess) - creator and maintainer
 - [Jerome Gravel-Niquet](https://github.com/jeromegn) - `HTTP::Client` and `OpenSSL` extensions from the original [docker.cr lib](https://github.com/jeromegn/docker.cr)

@@ -1,9 +1,8 @@
 name: docker
-version: 0.4.4
+version: 0.2.0
 crystal: ">= 0.36.1"
 license: MIT
 authors:
-  - Willi Wonka <willi.wonka38@proton.me>
   - Kim Burgess <kim@acaprojects.com>
   - Caspian Baska <email@caspian.computer>
 

src/docker/api/api_client.cr
@@ -9,7 +9,6 @@ require "../errors"
 require "./containers"
 require "./daemon"
 require "./images"
-require "./volumes"
 
 # Low-level wrapper for the Docker Engine API.
 #

...
@@ -33,7 +32,7 @@ class Docker::Api::ApiClient
 
     case uri.scheme
     when "unix"
-      # puts "unix socket connection to: #{@socket_path}\n"
+      puts "unix socket connection to: #{@socket_path}\n"
       @socket_path = @socket_path.gsub(/unix:\/\//, "")
       @socket = UNIXSocket.new(@socket_path)
     else

...
@@ -43,11 +42,7 @@ class Docker::Api::ApiClient
 
   {% for method in %w(get post put head delete patch options) %}
     # Builds and executes a GET/POST/... request on a unix socket.
-    def unix_{{method.id}}(
-      path : String,
-      headers : HTTP::Headers? = nil,
-      body : HTTP::Client::BodyType? = nil
-    )
+    def unix_{{method.id}}(path : String, headers : HTTP::Headers? = nil, body : String? = nil)
       headers ||= HTTP::Headers.new
       headers = headers.dup
 

...
@@ -100,28 +95,12 @@ class Docker::Api::ApiClient
         response
       end
 
-      # cleanup response body send over docker socket
       raw = res_str
-        .gsub("10f1\r\n", "") # ?
-        .gsub("10f", "")      # ?
         .gsub("11\r\n", "")   # ?
         .gsub("11c4\r\n", "") # ?
         .gsub("0\r\n", "")    # ?
-        .gsub("1321\r\n", "") # ?
-        .gsub("1322\r\n", "") # ?
-        .gsub("13\r\n", "")   # ?
-        .gsub("14\r\n", "")   # ?
-        .gsub("1d\r\n", "")   # ?
-        .gsub("4f\r\n", "")   # ?
-        .gsub("3a\r\n", "")   # ?
-        .gsub("3e\r\n", "")   # ?
-        .gsub("5e\r\n", "")   # ?
-
-      # pp path
-      # pp raw
-      # puts "\n"
-
-      # Parse status line, headers and body
+
+      # # Parse status line, headers and body
       head, body = raw.split("\r\n\r\n", 2)
       body = body.chomp("\r\n").chomp("\r\n")
       status_line, *header_lines = head.split("\r\n")

...
@@ -211,5 +190,4 @@ class Docker::Api::ApiClient
   include Containers
   include Daemon
   include Images
-  include Volumes
 end

src/docker/api/containers.cr
@@ -44,7 +44,9 @@ module Docker::Api::Containers
   #
   # Similar to the `docker start` command, but doesn’t support attach options.
   def start(id : String)
+    puts "start container id: #{id}\n"
     response = post "/containers/#{id}/start"
+    p! response
     nil
   end
 

...
@@ -116,63 +118,6 @@ module Docker::Api::Containers
     nil
   end
 
-  # Exec commands inside a container.
-  def exec(id : String, command : Array(String))
-    # create the exec request
-    props = {
-      "AttachStdout": true,
-      "AttachStderr": true,
-      "Cmd": command,
-      "Env": {
-        "FOO": "foo",
-      }, # make it configurable
-    }
-
-    exec_res = post "/containers/#{id}/exec", body: props.to_jsonbody
-    exec_id = JSON.parse(exec_res.body).as_h["Id"]
-
-    props = {
-      "Detach": false,
-      "Tty": false,
-    }
-
-    start_exec_res = post "/containers/#{id}/exec/start", body: props.to_json
-    nil
-  end
-
-  # Get logs from a container
-  def logs(
-    id : String,
-    stdout : Bool? = true,
-    stderr : Bool? = true,
-    follow : Bool? = true,
-  )
-    response = get "/containers/#{id}/logs?stdout=#{stdout ? 1 : 0}&stderr=#{stderr ? 1 : 0}&follow=#{follow ? 1 : 0}"
-    response.body
-  end
-
-  # Retrieve an archive from a container
-  def get_archive(id : String, path : String) : Bytes
-    params = HTTP::Params.build do |param|
-      param.add "path", path
-    end
-    response = get "/containers/#{id}/archive?#{params}"
-    response.body.to_slice
-  end
-
-  # Send an archive to a container
-  def put_archive(id : String, path : String, archive : Bytes)
-    headers = HTTP::Headers.new
-    headers["Content-Type"] = "application/x-tar"
-    headers["Content-Length"] = archive.size.to_s
-    params = HTTP::Params.build do |param|
-      param.add "path", path
-    end
-    body = archive.to_slice
-    response = put "/containers/#{id}/archive?#{params}", headers, body
-    response.body
-  end
-
   # Block until a container stops, then returns the exit code.
   #
   # Similar to `docker wait` command.

src/docker/api/images.cr
@@ -66,15 +66,4 @@ module Docker::Api::Images
     response = get "/images/#{id}/json"
     Models::Image.from_json response.body
   end
-
-  # Pull an image from a registry.
-  #
-  # Identical to the `docker pull` command.
-  def pull_image(name : String, tag : String? = nil)
-    params = HTTP::Params.build do |param|
-      param.add "fromImage", name
-      param.add "tag", tag.to_s unless tag.nil?
-    end
-    response = post "/images/create?#{params}"
-  end
 end

src/docker/api/models/container.cr
@@ -135,7 +135,7 @@ module Docker::Api::Models
       # @[JSON::Field(key: "KernelMemory")]
       # getter kernel_memory : Int32
       @[JSON::Field(key: "OomKillDisable")]
-      getter oom_kill_disable : Bool?
+      getter oom_kill_disable : Bool
       @[JSON::Field(key: "OomScoreAdj")]
       getter joom_score_adj : Int32
       @[JSON::Field(key: "NetworkMode")]

src/docker/api/models/image.cr
@@ -5,7 +5,7 @@ module Docker::Api::Models
     @[JSON::Field(key: "Id")]
     getter id : String
     @[JSON::Field(key: "Container")]
-    getter container : String?
+    getter container : String
     @[JSON::Field(key: "Comment")]
     getter comment : String
     @[JSON::Field(key: "Os")]

file deleted
src/docker/api/models/volume.cr
@@ -1,20 +0,0 @@
-require "./response"
-
-module Docker::Api::Models
-  struct Volume < Response
-    @[JSON::Field(key: "CreatedAt")]
-    getter created_at : String
-    @[JSON::Field(key: "Driver")]
-    getter driver : String
-    @[JSON::Field(key: "Labels")]
-    getter labels : Hash(String, String)?
-    @[JSON::Field(key: "Mountpoint")]
-    getter mountpoint : String
-    @[JSON::Field(key: "Name")]
-    getter name : String
-    @[JSON::Field(key: "Options")]
-    getter options : Hash(String, String)? # Docker::Api::Volume::Options
-    @[JSON::Field(key: "Scope")]
-    getter scope : String
-  end
-end

file deleted
src/docker/api/volumes.cr
@@ -1,20 +0,0 @@
-require "../../tools"
-require "./models/volume"
-
-# API queries for image interaction.
-module Docker::Api::Volumes
-  def list(filters : Hash(String, Array(String)))
-    response = @client.get("/volumes", query: filters)
-
-    Docker::Api::Models::Volume
-      .from_json_array(response.body)
-  end
-
-  def create(name : String)
-    body = { "Name" => name }.to_json
-    response = @client.post("/volumes/create", body: body)
-
-    Docker::Api::Models::Volume
-      .from_json(response.body)
-  end
-end

file deleted
src/docker/archive.cr
@@ -1,20 +0,0 @@
-require "./api_client_wrapper"
-require "./api/models/container"
-
-# Interact with a single container that exists on a docker client.
-class Docker::Archive
-  include Docker::ApiClientWrapper
-
-  def initialize(@client : Docker::Api::ApiClient, @id : String)
-  end
-
-  # Method to get an archive from container
-  def get(path : String)
-    @client.get_archive @id, path
-  end
-
-  # Method to send an archive to container
-  def put(path : String, archive : Bytes)
-    @client.put_archive @id, path, archive
-  end
-end

@@ -1,7 +1,6 @@
 require "./api_client_wrapper"
 require "./containers"
 require "./images"
-require "./volumes"
 
 # A client for communicating with a Docker server.
 #

...
@@ -16,18 +15,10 @@ class Docker::Client
     @client = Docker::Api::ApiClient.new base_url, @api_version
   end
 
-  # Provides access to container management.
-  def containers
-    Containers.new @client
-  end
-
-  # Provides access to image management.
-  def images
-    Images.new @client
-  end
-
-  # Provides access to volume management.
-  def volumes
-    Volumes.new @client
-  end
+  {% for component in %w(containers images) %}
+    # Provide an object for managing {{component.id}}. See `Docker::{{component.id.capitalize}}`.
+    def {{component.id}} : {{component.id.capitalize}}
+      @{{component.id}} ||= {{component.id.capitalize}}.new client
+    end
+  {% end %}
 end

src/docker/container.cr
@@ -1,8 +1,6 @@
 require "./api_client_wrapper"
 require "./api/models/container"
 
-require "./archive"
-
 # Interact with a single container that exists on a docker client.
 class Docker::Container
   include Docker::ApiClientWrapper

...
@@ -51,16 +49,6 @@ class Docker::Container
     attrs.state.status
   end
 
-  def archive
-    Docker::Archive.new(client, id)
-  end
-
-  # Run command inside the container.
-  def exec(command : Array(String))
-    client.exec id, command
-    self
-  end
-
   # Start this container.
   def start
     client.start id

...
@@ -126,11 +114,6 @@ class Docker::Container
     self
   end
 
-  # Get logs from the container.
-  def logs
-    client.logs id
-  end
-
   # Block until the container stops, then return its exit code.
   def wait(condition = nil)
     response = client.wait id, condition

@@ -58,13 +58,4 @@ class Docker::Images
     image_ids = client.images(all, name, filters).map &.id
     image_ids.map &->get(String)
   end
-
-  # Pull an image from a registry.
-  def pull(image : String, tag : String? = nil)
-    parts = image.split(":")
-    name = parts.first
-    tag = parts.last if tag.nil?
-
-    client.pull_image(name, tag)
-  end
 end

file deleted
src/docker/volumes.cr
@@ -1,21 +0,0 @@
-require "./api_client_wrapper"
-require "./api/models/volume"
-
-# Interact with a single container that exists on a docker client.
-class Docker::Volumes
-  include Docker::ApiClientWrapper
-
-  def initialize(@client : Docker::Api::ApiClient)
-  end
-
-  # Method to get an archive from container
-  def list(filters : Hash(String, Array(String)))
-    # filters: { "name" => [vid] }
-    @client.list_volume filters
-  end
-
-  # Method to send an archive to container
-  def create(name : String)
-    @client.create_volume name
-  end
-end