allow user to specify a single port with default command
Allows specifying `-p9999` or `-p5555:9999` without also needing to override the default command
app retrieves port arguments from length-1 port mapping for default command,
instead of requiring random port OR overriding the whole command
MODIFY
repo2docker/__main__.py
repo2docker/__main__.py
@@ -354,7 +354,7 @@ def make_r2d(argv=None):
)
sys.exit(1)
- if args.ports and not r2d.run_cmd:
+ if args.ports and len(args.ports) > 1 and not r2d.run_cmd:
print(
"To publish user defined port mapping, user must specify "
"the command to run in the container"

MODIFY
repo2docker/app.py
repo2docker/app.py
@@ -595,8 +595,24 @@ class Repo2Docker(Application):
self.hostname = host_name
if not self.run_cmd:
- port = str(self._get_free_port())
- self.port = port
+ if len(self.ports) == 1:
+ # single port mapping specified
+ # retrieve container and host port from dict
+ # {'8888/tcp': ('hostname', 'port')}
+ # or
+ # {'8888/tcp': 'port'}
+ container_port_proto, host_port = next(iter(self.ports.items()))
+ if isinstance(host_port, tuple):
+ # (hostname, port) tuple or string port
+ host_name, host_port = host_port
+ self.hostname = host_name
+ host_port = int(host_port)
+ container_port = int(container_port_proto.split("/", 1)[0])
+ else:
+ # no port specified, pick a random one
+ container_port = host_port = str(self._get_free_port())
+ self.ports = {"%s/tcp" % container_port: host_port}
+ self.port = host_port
# To use the option --NotebookApp.custom_display_url
# make sure the base-notebook image is updated:
# docker pull jupyter/base-notebook
@@ -606,20 +622,13 @@ class Repo2Docker(Application):
"--ip",
"0.0.0.0",
"--port",
- port,
- "--NotebookApp.custom_display_url=http://{}:{}".format(host_name, port),
+ container_port,
+ f"--NotebookApp.custom_display_url=http://{host_name}:{host_port}"
"--NotebookApp.default_url=/lab",
]
- ports = {"%s/tcp" % port: port}
else:
# run_cmd given by user, if port is also given then pass it on
run_cmd = self.run_cmd
- if self.ports:
- ports = self.ports
- else:
- ports = {}
- # store ports on self so they can be retrieved in tests
- self.ports = ports
container_volumes = {}
if self.volumes:
@@ -634,7 +643,7 @@ class Repo2Docker(Application):
run_kwargs = dict(
publish_all_ports=self.all_ports,
- ports=ports,
+ ports=self.ports,
command=run_cmd,
volumes=container_volumes,
environment=self.environment,

MODIFY
repo2docker/utils.py
repo2docker/utils.py
@@ -139,10 +139,10 @@ def validate_and_generate_port_mapping(port_mappings):
raise ValueError(
'Port specification "{}" has ' "an invalid port.".format(mapping)
)
- if p > 65535:
+ if not 0 < p <= 65535:
raise ValueError(
'Port specification "{}" specifies '
- "a port above 65535.".format(mapping)
+ "a port outside 1-65535.".format(mapping)
)
return port
@@ -168,7 +168,12 @@ def validate_and_generate_port_mapping(port_mappings):
return ports
for mapping in port_mappings:
+ if ":" in mapping:
parts = mapping.split(":")
+ else:
+ # single port '8888' specified,
+ # treat as '8888:8888'
+ parts = [mapping, mapping]
*host, container_port = parts
# just a port

allow user to specify a single port with default command

Allows specifying `-p9999` or `-p5555:9999` without also needing to override the default command

app retrieves port arguments from length-1 port mapping for default command,
instead of requiring random port OR overriding the whole command