Repository: compose-spec/compose-go
Pull request #192 (2021-09-29 07:24:36)

allow tmpfs.size to be set in unit bytes
see https://github.com/compose-spec/compose-spec/pull/205

Close https://github.com/docker/compose/issues/8696


Patch:
diff --git a/loader/interpolate.go b/loader/interpolate.go
index 5cfa84b..4425444 100644
--- a/loader/interpolate.go
+++ b/loader/interpolate.go
@@ -67,6 +67,7 @@ var interpolateTypeCastMapping = map[interp.Path]interp.Cast{
 	servicePath("ulimits", interp.PathMatchAll, "soft"):              toInt,
 	servicePath("volumes", interp.PathMatchList, "read_only"):        toBoolean,
 	servicePath("volumes", interp.PathMatchList, "volume", "nocopy"): toBoolean,
+	servicePath("volumes", interp.PathMatchList, "tmpfs", "size"):    toUnitBytes,
 	iPath("networks", interp.PathMatchAll, "external"):               toBoolean,
 	iPath("networks", interp.PathMatchAll, "internal"):               toBoolean,
 	iPath("networks", interp.PathMatchAll, "attachable"):             toBoolean,
diff --git a/schema/compose-spec.json b/schema/compose-spec.json
index 6d9c7c2..91bdb34 100644
--- a/schema/compose-spec.json
+++ b/schema/compose-spec.json
@@ -331,7 +331,7 @@
         "privileged": {"type": "boolean"},
         "profiles": {"$ref": "#/definitions/list_of_strings"},
         "pull_policy": {"type": "string", "enum": [
-          "always", "never", "if_not_present", "build"
+          "always", "never", "if_not_present", "build", "missing"
         ]},
         "read_only": {"type": "boolean"},
         "restart": {"type": "string"},
@@ -367,6 +367,7 @@
         "stdin_open": {"type": "boolean"},
         "stop_grace_period": {"type": "string", "format": "duration"},
         "stop_signal": {"type": "string"},
+        "storage_opt": {"type": "object"},
         "tmpfs": {"$ref": "#/definitions/string_or_list"},
         "tty": {"type": "boolean"},
         "ulimits": {
@@ -426,8 +427,10 @@
                     "type": "object",
                     "properties": {
                       "size": {
-                        "type": "integer",
-                        "minimum": 0
+                        "oneOf": [
+                          {"type": "integer", "minimum": 0},
+                          {"type": "string"}
+                        ]
                       }
                     },
                     "additionalProperties": false,
@@ -599,12 +602,12 @@
       "items": {
         "type": "object",
         "properties": {
-          "capabilities": {"$ref": "#/definitions/list_of_strings"},
-          "count": {"type": ["string", "integer"]},
-          "device_ids": {"$ref": "#/definitions/list_of_strings"},
-          "driver":{"type": "string"},
-          "options":{"$ref": "#/definitions/list_or_dict"}
-        },
+            "capabilities": {"$ref": "#/definitions/list_of_strings"},
+            "count": {"type": ["string", "integer"]},
+            "device_ids": {"$ref": "#/definitions/list_of_strings"},
+            "driver":{"type": "string"},
+            "options":{"$ref": "#/definitions/list_or_dict"}
+          },
         "additionalProperties": false,
         "patternProperties": {"^x-": {}}
       }
@@ -810,4 +813,4 @@
       }
     }
   }
-}
\ No newline at end of file
+}
diff --git a/types/types.go b/types/types.go
index 23bae0e..09ed1e7 100644
--- a/types/types.go
+++ b/types/types.go
@@ -690,7 +690,7 @@ type ServiceVolumeVolume struct {
 
 // ServiceVolumeTmpfs are options for a service volume of type tmpfs
 type ServiceVolumeTmpfs struct {
-	Size int64 `yaml:",omitempty" json:"size,omitempty"`
+	Size UnitBytes `yaml:",omitempty" json:"size,omitempty"`
 
 	Extensions map[string]interface{} `yaml:",inline" json:"-"`
 }


Test patch:
diff --git a/loader/full-struct_test.go b/loader/full-struct_test.go
index 751a553..a81e047 100644
--- a/loader/full-struct_test.go
+++ b/loader/full-struct_test.go
@@ -403,7 +403,7 @@ func services(workingDir, homeDir string) []types.ServiceConfig {
 				{Source: "datavolume", Target: "/var/lib/mysql", Type: "volume", Volume: &types.ServiceVolumeVolume{}},
 				{Source: filepath.Join(workingDir, "opt"), Target: "/opt", Consistency: "cached", Type: "bind"},
 				{Target: "/opt", Type: "tmpfs", Tmpfs: &types.ServiceVolumeTmpfs{
-					Size: int64(10000),
+					Size: types.UnitBytes(10000),
 				}},
 			},
 			WorkingDir: "/code",
@@ -866,7 +866,7 @@ func fullExampleYAML(workingDir, homeDir string) string {
     - type: tmpfs
       target: /opt
       tmpfs:
-        size: 10000
+        size: "10000"
     working_dir: /code
     x-bar: baz
     x-foo: bar
@@ -1503,7 +1503,7 @@ func fullExampleJSON(workingDir, homeDir string) string {
           "type": "tmpfs",
           "target": "/opt",
           "tmpfs": {
-            "size": 10000
+            "size": "10000"
           }
         }
       ],
diff --git a/loader/loader_test.go b/loader/loader_test.go
index cea5117..b814d81 100644
--- a/loader/loader_test.go
+++ b/loader/loader_test.go
@@ -18,6 +18,7 @@ package loader
 
 import (
 	"bytes"
+	"fmt"
 	"io/ioutil"
 	"os"
 	"sort"
@@ -928,29 +929,32 @@ func TestFullExample(t *testing.T) {
 }
 
 func TestLoadTmpfsVolume(t *testing.T) {
-	config, err := loadYAML(`
+	for _, size := range []string{"1kb", "1024"} {
+		yaml := fmt.Sprintf(`
 services:
   tmpfs:
     image: nginx:latest
     volumes:
-      - type: tmpfs
-        target: /app
-        tmpfs:
-          size: 10000
-`)
-	assert.NilError(t, err)
+    - type: tmpfs
+      target: /app
+      tmpfs:
+        size: %s
+`, size)
+		config, err := loadYAML(yaml)
+		assert.NilError(t, err)
+
+		expected := types.ServiceVolumeConfig{
+			Target: "/app",
+			Type:   "tmpfs",
+			Tmpfs: &types.ServiceVolumeTmpfs{
+				Size: types.UnitBytes(1024),
+			},
+		}
 
-	expected := types.ServiceVolumeConfig{
-		Target: "/app",
-		Type:   "tmpfs",
-		Tmpfs: &types.ServiceVolumeTmpfs{
-			Size: int64(10000),
-		},
+		assert.Assert(t, is.Len(config.Services, 1))
+		assert.Check(t, is.Len(config.Services[0].Volumes, 1))
+		assert.Check(t, is.DeepEqual(expected, config.Services[0].Volumes[0]))
 	}
-
-	assert.Assert(t, is.Len(config.Services, 1))
-	assert.Check(t, is.Len(config.Services[0].Volumes, 1))
-	assert.Check(t, is.DeepEqual(expected, config.Services[0].Volumes[0]))
 }
 
 func TestLoadTmpfsVolumeAdditionalPropertyNotAllowed(t *testing.T) {