Update build and deploy process, otherwise unchanged
diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..550bd25
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,2 @@
+Makefile
+
diff --git a/Dockerfile.2.7 b/Dockerfile.2.7
deleted file mode 100644
index b61ae90..0000000
--- a/Dockerfile.2.7
+++ /dev/null
@@ -1,14 +0,0 @@
-FROM python:2.7
-WORKDIR /app
-
-COPY requirements.txt .
-
-RUN python2.7 -m pip install -r requirements.txt
-
-# need crontab
-COPY crontab/*.py crontab/
-# and need the tests too
-COPY tests/* crontab_tests/
-
-# Note: needs access to Redis; assumes localhost:6879
-CMD ["python2.7", "-m", "crontab_tests.test_crontab"]
diff --git a/Dockerfile.3.10 b/Dockerfile.3.10
deleted file mode 100644
index 9ac61c6..0000000
--- a/Dockerfile.3.10
+++ /dev/null
@@ -1,15 +0,0 @@
-FROM python:3.10-bullseye
-
-WORKDIR /app
-
-COPY requirements.txt .
-
-RUN python3.10 -m pip install -r requirements.txt
-
-# need crontab
-COPY crontab/*.py crontab/
-# and need the tests too
-COPY tests/* crontab_tests/
-
-# Note: needs access to Redis; assumes localhost:6879
-CMD ["python3.10", "-m", "crontab_tests.test_crontab"]
diff --git a/Dockerfile.3.11 b/Dockerfile.3.11
deleted file mode 100644
index e48d2dc..0000000
--- a/Dockerfile.3.11
+++ /dev/null
@@ -1,15 +0,0 @@
-FROM python:3.11-bullseye
-
-WORKDIR /app
-
-COPY requirements.txt .
-
-RUN python3.11 -m pip install -r requirements.txt
-
-# need crontab
-COPY crontab/*.py crontab/
-# and need the tests too
-COPY tests/* crontab_tests/
-
-# Note: needs access to Redis; assumes localhost:6879
-CMD ["python3.11", "-m", "crontab_tests.test_crontab"]
diff --git a/Dockerfile.3.3 b/Dockerfile.3.3
deleted file mode 100644
index 75a29a0..0000000
--- a/Dockerfile.3.3
+++ /dev/null
@@ -1,15 +0,0 @@
-FROM python:3.3
-
-WORKDIR /app
-
-COPY requirements.txt .
-
-RUN python3.3 -m pip install -r requirements.txt
-
-# need crontab
-COPY crontab/*.py crontab/
-# and need the tests too
-COPY tests/* crontab_tests/
-
-# Note: needs access to Redis; assumes localhost:6879
-CMD ["python3.3", "-m", "crontab_tests.test_crontab"]
diff --git a/Dockerfile.3.4 b/Dockerfile.3.4
deleted file mode 100644
index d16a787..0000000
--- a/Dockerfile.3.4
+++ /dev/null
@@ -1,15 +0,0 @@
-FROM python:3.4
-
-WORKDIR /app
-
-COPY requirements.txt .
-
-RUN python3.4 -m pip install -r requirements.txt
-
-# need crontab
-COPY crontab/*.py crontab/
-# and need the tests too
-COPY tests/* crontab_tests/
-
-# Note: needs access to Redis; assumes localhost:6879
-CMD ["python3.4", "-m", "crontab_tests.test_crontab"]
diff --git a/Dockerfile.3.5 b/Dockerfile.3.5
deleted file mode 100644
index b5e6099..0000000
--- a/Dockerfile.3.5
+++ /dev/null
@@ -1,15 +0,0 @@
-FROM python:3.5
-
-WORKDIR /app
-
-COPY requirements.txt .
-
-RUN python3.5 -m pip install -r requirements.txt
-
-# need crontab
-COPY crontab/*.py crontab/
-# and need the tests too
-COPY tests/* crontab_tests/
-
-# Note: needs access to Redis; assumes localhost:6879
-CMD ["python3.5", "-m", "crontab_tests.test_crontab"]
diff --git a/Dockerfile.3.6 b/Dockerfile.3.6
deleted file mode 100644
index 95b10a0..0000000
--- a/Dockerfile.3.6
+++ /dev/null
@@ -1,15 +0,0 @@
-FROM python:3.6
-
-WORKDIR /app
-
-COPY requirements.txt .
-
-RUN python3.6 -m pip install -r requirements.txt
-
-# need crontab
-COPY crontab/*.py crontab/
-# and need the tests too
-COPY tests/* crontab_tests/
-
-# Note: needs access to Redis; assumes localhost:6879
-CMD ["python3.6", "-m", "crontab_tests.test_crontab"]
diff --git a/Dockerfile.3.7 b/Dockerfile.3.7
deleted file mode 100644
index d1b138a..0000000
--- a/Dockerfile.3.7
+++ /dev/null
@@ -1,15 +0,0 @@
-FROM python:3.7-bullseye
-
-WORKDIR /app
-
-COPY requirements.txt .
-
-RUN python3.7 -m pip install -r requirements.txt
-
-# need crontab
-COPY crontab/*.py crontab/
-# and need the tests too
-COPY tests/* crontab_tests/
-
-# Note: needs access to Redis; assumes localhost:6879
-CMD ["python3.7", "-m", "crontab_tests.test_crontab"]
diff --git a/Dockerfile.3.8 b/Dockerfile.3.8
deleted file mode 100644
index aa2b52b..0000000
--- a/Dockerfile.3.8
+++ /dev/null
@@ -1,15 +0,0 @@
-FROM python:3.8-bullseye
-
-WORKDIR /app
-
-COPY requirements.txt .
-
-RUN python3.8 -m pip install -r requirements.txt
-
-# need crontab
-COPY crontab/*.py crontab/
-# and need the tests too
-COPY tests/* crontab_tests/
-
-# Note: needs access to Redis; assumes localhost:6879
-CMD ["python3.8", "-m", "crontab_tests.test_crontab"]
diff --git a/Dockerfile.3.9 b/Dockerfile.3.9
deleted file mode 100644
index db42c8a..0000000
--- a/Dockerfile.3.9
+++ /dev/null
@@ -1,15 +0,0 @@
-FROM python:3.9-bullseye
-
-WORKDIR /app
-
-COPY requirements.txt .
-
-RUN python3.9 -m pip install -r requirements.txt
-
-# need crontab
-COPY crontab/*.py crontab/
-# and need the tests too
-COPY tests/* crontab_tests/
-
-# Note: needs access to Redis; assumes localhost:6879
-CMD ["python3.9", "-m", "crontab_tests.test_crontab"]
diff --git a/Dockerfile.bullseye b/Dockerfile.bullseye
new file mode 100644
index 0000000..0fcd40e
--- /dev/null
+++ b/Dockerfile.bullseye
@@ -0,0 +1,20 @@
+ARG PYTHON_VERSION="3.11"
+
+FROM python:${PYTHON_VERSION}-bullseye
+ARG PYTHON_VERSION
+ARG PY="python${PYTHON_VERSION}"
+
+ENV PYTHON_VERSION=$PYTHON_VERSION
+
+WORKDIR /app
+
+RUN ${PY} -m pip install --upgrade pip
+COPY requirements_old.txt .
+RUN ${PY} -m pip install -r requirements_old.txt
+
+# need crontab
+COPY crontab/*.py crontab/
+# and need the tests too
+COPY tests/* crontab_tests/
+
+CMD ${PY} -m crontab_tests.test_crontab
diff --git a/Dockerfile.generic b/Dockerfile.generic
new file mode 100644
index 0000000..d7bfe3e
--- /dev/null
+++ b/Dockerfile.generic
@@ -0,0 +1,20 @@
+ARG PYTHON_VERSION="2.7"
+
+FROM python:${PYTHON_VERSION}
+ARG PYTHON_VERSION
+ARG PY="python${PYTHON_VERSION}"
+
+ENV PYTHON_VERSION=$PYTHON_VERSION
+
+WORKDIR /app
+
+RUN ${PY} -m pip install --upgrade pip
+COPY requirements_old.txt .
+RUN ${PY} -m pip install -r requirements_old.txt
+
+# need crontab
+COPY crontab/*.py crontab/
+# and need the tests too
+COPY tests/* crontab_tests/
+
+CMD ${PY} -m crontab_tests.test_crontab
diff --git a/Dockerfile.upload b/Dockerfile.upload
new file mode 100644
index 0000000..88df1fd
--- /dev/null
+++ b/Dockerfile.upload
@@ -0,0 +1,20 @@
+ARG PYTHON_VERSION="3.11"
+
+FROM python:${PYTHON_VERSION}-bullseye
+ARG PYTHON_VERSION
+ARG PY="python${PYTHON_VERSION}"
+
+ENV PYTHON_VERSION=$PYTHON_VERSION
+
+WORKDIR /app
+
+RUN ${PY} -m pip install --upgrade pip
+COPY requirements.txt .
+RUN ${PY} -m pip install -r requirements.txt
+
+# need crontab
+COPY crontab/*.py crontab/
+# and need the tests too
+COPY tests/* crontab_tests/
+
+CMD ${PY} -m crontab_tests.test_crontab
diff --git a/Makefile b/Makefile
index bb41a04..d7af125 100644
--- a/Makefile
+++ b/Makefile
@@ -5,9 +5,7 @@
 # The sed removes extra spaces and colons
 # Which we pass into our rebuild
 GET_TARGET=grep crontab-test $${target} | sed 's/[ :]//g'
-GET_TARGET2=grep crontab-test docker-compose.$${target}.yaml | sed 's/[ :]//g'
-DASH_TO_DOTS=sed 's/[-]/\./g'
-COMPOSE_PREFIX=docker-compose -f docker-compose.
+GET_TARGET2=grep crontab-test-$${target} docker-compose.yaml | sed 's/[ :]//g'
 
 SHELL=/bin/bash
 # You can set these variables from the command line.
@@ -24,46 +22,34 @@
 
 .PHONY: clean docs test
 
-default:
-	find . -type f | xargs chmod -x
+default: perms
+	find . -type f | sudo xargs chmod -x
 
-clean:
+perms:
+	-sudo chown ${USER}:${USER} -R .
+
+clean: default
 	-rm -f *.pyc crontab/*.pyc README.html MANIFEST
-	-rm -rf build dist
-
-install:
-	python setup.py install
-
+	-rm -rf build crontab.egg-info
 
 compose-build-all:
-	for target in ${FILES} ; do \
-		docker-compose -f $${target} build `${GET_TARGET}`; \
-	done
+	docker-compose build
 
 compose-build-%:
 	for target in $(patsubst compose-build-%,%,$@) ; do \
-		${COMPOSE_PREFIX}$${target}.yaml build `${GET_TARGET2}`; \
-	done
-
-compose-up-%:
-	for target in $(patsubst compose-up-%,%,$@) ; do \
-		${COMPOSE_PREFIX}$${target}.yaml up --remove-orphans `${GET_TARGET2}`; \
-	done
-
-compose-down-%:
-	for target in $(patsubst compose-down-%,%,$@) ; do \
-		${COMPOSE_PREFIX}$${target}.yaml down `${GET_TARGET2}`; \
+		docker-compose build `${GET_TARGET2}`; \
 	done
 
 testall:
-	make -j1 test-3.11 test-3.10 test-3.9 test-3.8 test-3.7 test-3.6 test-3.5 test-3.4 test-2.7
+	make -j1 test-3.13 test-3.12 test-3.11 test-3.10 test-3.9 test-3.8 test-3.7 test-3.6 test-3.5 test-3.4 test-2.7
 
 test-%:
 	# the test container runs the tests on up, then does an exit 0 when done
 	for target in $(patsubst test-%,%,$@) ; do \
-		make compose-build-$${target} && make compose-up-$${target}; \
+		docker-compose run --rm `${GET_TARGET2}` ; \
 	done
 
 upload:
-	python3.6 setup.py sdist upload
-
+	docker-compose run --rm -w /source crontab-test-uploader python3.13 -m build --sdist
+	docker-compose run --rm -w /source crontab-test-uploader python3.13 -m twine upload --skip-existing dist/*.tar.gz
+	make perms
diff --git a/docker-compose.2.7.yaml b/docker-compose.2.7.yaml
deleted file mode 100644
index 578cf7f..0000000
--- a/docker-compose.2.7.yaml
+++ /dev/null
@@ -1,9 +0,0 @@
-version: '3.9'
-services:
-  crontab-test-2-7:
-    build:
-      context: .
-      dockerfile: Dockerfile.2.7
-    environment:
-      PYTHONPATH: /app
-
diff --git a/docker-compose.3.10.yaml b/docker-compose.3.10.yaml
deleted file mode 100644
index 86e8e94..0000000
--- a/docker-compose.3.10.yaml
+++ /dev/null
@@ -1,8 +0,0 @@
-version: '3.9'
-services:
-  crontab-test-3-10:
-    build:
-      context: .
-      dockerfile: Dockerfile.3.10
-    environment:
-      PYTHONPATH: /app
diff --git a/docker-compose.3.11.yaml b/docker-compose.3.11.yaml
deleted file mode 100644
index 9c2d790..0000000
--- a/docker-compose.3.11.yaml
+++ /dev/null
@@ -1,8 +0,0 @@
-version: '3.9'
-services:
-  crontab-test-3-11:
-    build:
-      context: .
-      dockerfile: Dockerfile.3.11
-    environment:
-      PYTHONPATH: /app
diff --git a/docker-compose.3.3.yaml b/docker-compose.3.3.yaml
deleted file mode 100644
index f0d4159..0000000
--- a/docker-compose.3.3.yaml
+++ /dev/null
@@ -1,8 +0,0 @@
-version: '3.'
-services:
-  crontab-test-3-3:
-    build:
-      context: .
-      dockerfile: Dockerfile.3.3
-    environment:
-      PYTHONPATH: /app
diff --git a/docker-compose.3.4.yaml b/docker-compose.3.4.yaml
deleted file mode 100644
index a9488cc..0000000
--- a/docker-compose.3.4.yaml
+++ /dev/null
@@ -1,8 +0,0 @@
-version: '3.'
-services:
-  crontab-test-3-4:
-    build:
-      context: .
-      dockerfile: Dockerfile.3.4
-    environment:
-      PYTHONPATH: /app
diff --git a/docker-compose.3.5.yaml b/docker-compose.3.5.yaml
deleted file mode 100644
index 96f66d9..0000000
--- a/docker-compose.3.5.yaml
+++ /dev/null
@@ -1,8 +0,0 @@
-version: '3.9'
-services:
-  crontab-test-3-5:
-    build:
-      context: .
-      dockerfile: Dockerfile.3.5
-    environment:
-      PYTHONPATH: /app
diff --git a/docker-compose.3.6.yaml b/docker-compose.3.6.yaml
deleted file mode 100644
index e23375a..0000000
--- a/docker-compose.3.6.yaml
+++ /dev/null
@@ -1,8 +0,0 @@
-version: '3.9'
-services:
-  crontab-test-3-6:
-    build:
-      context: .
-      dockerfile: Dockerfile.3.6
-    environment:
-      PYTHONPATH: /app
diff --git a/docker-compose.3.7.yaml b/docker-compose.3.7.yaml
deleted file mode 100644
index 0e8e950..0000000
--- a/docker-compose.3.7.yaml
+++ /dev/null
@@ -1,8 +0,0 @@
-version: '3.9'
-services:
-  crontab-test-3-7:
-    build:
-      context: .
-      dockerfile: Dockerfile.3.7
-    environment:
-      PYTHONPATH: /app
diff --git a/docker-compose.3.8.yaml b/docker-compose.3.8.yaml
deleted file mode 100644
index 938b40a..0000000
--- a/docker-compose.3.8.yaml
+++ /dev/null
@@ -1,8 +0,0 @@
-version: '3.9'
-services:
-  crontab-test-3-8:
-    build:
-      context: .
-      dockerfile: Dockerfile.3.8
-    environment:
-      PYTHONPATH: /app
diff --git a/docker-compose.3.9.yaml b/docker-compose.3.9.yaml
deleted file mode 100644
index a12063f..0000000
--- a/docker-compose.3.9.yaml
+++ /dev/null
@@ -1,8 +0,0 @@
-version: '3.9'
-services:
-  crontab-test-3-9:
-    build:
-      context: .
-      dockerfile: Dockerfile.3.9
-    environment:
-      PYTHONPATH: /app
diff --git a/docker-compose.yaml b/docker-compose.yaml
new file mode 100644
index 0000000..f5b528f
--- /dev/null
+++ b/docker-compose.yaml
@@ -0,0 +1,122 @@
+version: '3.3'
+services:
+  crontab-test-uploader:
+    build:
+      context: .
+      dockerfile: Dockerfile.upload
+      args:
+        PYTHON_VERSION: "3.13"
+    environment:
+      PYTHONPATH: /app
+      PY: python3.13
+    volumes:
+      - ./:/source/:rw
+      - ~/.pypirc/:/root/.pypirc/:ro
+
+  crontab-test-3-13:
+    build:
+      context: .
+      dockerfile: Dockerfile.bullseye
+      args:
+        PYTHON_VERSION: "3.13"
+    environment:
+      PYTHONPATH: /app
+      PY: python3.13
+  crontab-test-3-12:
+    build:
+      context: .
+      dockerfile: Dockerfile.bullseye
+      args:
+        PYTHON_VERSION: "3.12"
+    environment:
+      PYTHONPATH: /app
+      PY: python3.12
+  crontab-test-3-11:
+    build:
+      context: .
+      dockerfile: Dockerfile.bullseye
+      args:
+        PYTHON_VERSION: "3.11"
+    environment:
+      PYTHONPATH: /app
+      PY: python3.11
+  crontab-test-3-10:
+    build:
+      context: .
+      dockerfile: Dockerfile.bullseye
+      args:
+        PYTHON_VERSION: "3.10"
+    environment:
+      PYTHONPATH: /app
+      PY: python3.10
+  crontab-test-3-9:
+    build:
+      context: .
+      dockerfile: Dockerfile.bullseye
+      args:
+        PYTHON_VERSION: "3.9"
+    environment:
+      PYTHONPATH: /app
+      PY: python3.9
+  crontab-test-3-8:
+    build:
+      context: .
+      dockerfile: Dockerfile.bullseye
+      args:
+        PYTHON_VERSION: "3.8"
+    environment:
+      PYTHONPATH: /app
+      PY: python3.8
+  crontab-test-3-7:
+    build:
+      context: .
+      dockerfile: Dockerfile.bullseye
+      args:
+        PYTHON_VERSION: "3.7"
+    environment:
+      PYTHONPATH: /app
+      PY: python3.7
+  crontab-test-3-6:
+    build:
+      context: .
+      dockerfile: Dockerfile.generic
+      args:
+        PYTHON_VERSION: "3.6"
+    environment:
+      PYTHONPATH: /app
+      PY: python3.6
+  crontab-test-3-5:
+    build:
+      context: .
+      dockerfile: Dockerfile.generic
+      args:
+        PYTHON_VERSION: "3.5"
+    environment:
+      PYTHONPATH: /app
+      PY: python3.5
+  crontab-test-3-4:
+    build:
+      context: .
+      dockerfile: Dockerfile.generic
+      args:
+        PYTHON_VERSION: "3.4"
+    environment:
+      PYTHONPATH: /app
+      PY: python3.4
+  # crontab-test-3-3:
+  #   build:
+  #     context: .
+  #     dockerfile: Dockerfile.generic
+  #     args:
+  #       PYTHON_VERSION: "3.3"
+  #   environment:
+  #     PYTHONPATH: /app
+  crontab-test-2-7:
+    build:
+      context: .
+      dockerfile: Dockerfile.generic
+      args:
+        PYTHON_VERSION: "2.7"
+    environment:
+      PYTHONPATH: /app
+      PY: python2.7
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
index 63c031d..52583db 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,2 +1,5 @@
+build
 python-dateutil
-pytz
\ No newline at end of file
+pytz
+setuptools
+twine
\ No newline at end of file
diff --git a/requirements_old.txt b/requirements_old.txt
new file mode 100644
index 0000000..0aa987b
--- /dev/null
+++ b/requirements_old.txt
@@ -0,0 +1,2 @@
+python-dateutil
+pytz
diff --git a/setup.py b/setup.py
index a2c3d34..fd400f9 100644
--- a/setup.py
+++ b/setup.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 
-from distutils.core import setup
+from setuptools import setup
 
 try:
     with open('README.rst') as f:
@@ -10,7 +10,7 @@
 
 setup(
     name='crontab',
-    version='1.0.1',
+    version='1.0.2',
     description='Parse and use crontab schedules in Python',
     author='Josiah Carlson',
     author_email='[email protected]',
@@ -24,7 +24,6 @@
         'Programming Language :: Python',
         'Programming Language :: Python :: 2.7',
         'Programming Language :: Python :: 3.2',
-        'Programming Language :: Python :: 3.3',
         'Programming Language :: Python :: 3.4',
         'Programming Language :: Python :: 3.5',
         'Programming Language :: Python :: 3.6',
@@ -33,6 +32,8 @@
         'Programming Language :: Python :: 3.9',
         'Programming Language :: Python :: 3.10',
         'Programming Language :: Python :: 3.11',
+        'Programming Language :: Python :: 3.12',
+        'Programming Language :: Python :: 3.13',
     ],
     license='GNU LGPL v2.1',
     long_description=long_description,