This tool helps to download specific versions of the cqlsh utility from 2025.1 and 2025.2 releases. It provides command to list of available versions and another command to download a given version. All current downloadable files can be found at https://downloads.scylladb.com/downloads/scylla/relocatable/ To see whether each version is available on Scylla Cloud fetch this information from the https://api.cloud.scylladb.com/deployment/scylla-versions
-
Commands:
-
list: shows all available versions of cqlsh for download and availability in ScyllaDB Cloud.
- Optional -lt flag accepted to show only versions that are less than the specified value.
- Optional -gt flag accepted to show only versions that are greater than the user-specified value.
- Flags -lt and -gt could be combined to select the specified exclusive range.
- Flags -lt and -gt accept version values like X or X.Y or X.Y.Z or X.Y.Z~rcN. X, Y, Z, N are numbers.
-
download: fetches the archive of the specified version and outputs the downloaded file to STDOUT.
-
-
Syntax:
cqlshutil list [-lt <archive-version>] [-gt <archive-version>]cqlshutil download <archive-version>cqlshutil help -
Examples:
$ ./cqlshutil list
$ ./cqlshutil list -lt 2025.1.5
$ ./cqlshutil list -gt 2025.1.0~rc0
$ ./cqlshutil list -gt 2025.1 -lt 2025.2.0~rc1
$ ./cqlshutil download 2025.2.1 > cqlsh.tar.gz
$ ./cqlshutil helpThis project adopts a simple structure to make easy to understand and navigate into the codebase. There are 4 folders where 3 are go packages and 1 is just a folder containing tests data / assets.
The core package is represented by the app folder. It contains all key services routines used by list and download commands. It is exposed with a Service interface which makes easy to extend the functionalities and unit testing more flexible.
The other package is represented by testhelpers folder. It provides essentials routines to build
unit tests and perform assertions during those tests. It contains some mocks for http client and http servers involved into during operation of service calls.
The last package is represented by cmd folder. This is the entry point of the program. The main function is hosted there. Commands and arguments parsing are inside this package.
Finally the testdata folder contains 3 files which mimic real dataset fetched from official page and api endpoint. Those data are used during unit and functional tests inside the app package. This to ensure robust tests. sycalla-versions.json file contains some scylla versions into json format. archives-versions.2025.1.xml and archives-versions.2025.2.xml files contains data that mimic each download page contents since this program deals with 2 minor releases 2025.1 and 2025.2. There are mocked server into the testhelpers package that serve those files depending on the request URL.
One key important details about the design is using download command will firstly trigger the fetching of all available archives versions in order to build the archive direct download url, after which tthe real archive file downloading will take place. This to avoid dumping temporary data into file on disk which could lead to some issues depending on the environment and use case.
- adding
-eqflag on list command could help quick check availability of specific version - adding a timeout could help auto terminate so avoid waiting in case the http call is hanging
- adding a shutdown mechanism with signal handling could help controlling termination in case the tool is running into an automated manner
% go build -o dist/cqlshutil cmd/cqlshutil/*% chmod +x dist/cqlshutil% dist/cqlshutil list
VERSION CLOUD
2025.1.0 DISABLED
2025.1.0~rc0 N/A
2025.1.0~rc1 N/A
2025.1.0~rc2 N/A
2025.1.0~rc3 N/A
2025.1.0~rc4 N/A
2025.1.1 DISABLED
2025.1.2 DISABLED
2025.1.3 DISABLED
2025.1.4 DISABLED
2025.1.5 DISABLED
2025.2.0 DISABLED
2025.2.0~rc0 N/A
2025.2.0~rc1 N/A
2025.2.1 ENABLED
% dist/cqlshutil list -lt 2025.1.1
VERSION CLOUD
2025.1.0 DISABLED
2025.1.0~rc0 N/A
2025.1.0~rc1 N/A
2025.1.0~rc2 N/A
2025.1.0~rc3 N/A
2025.1.0~rc4 N/A
% dist/cqlshutil list -gt 2025.2.0
VERSION CLOUD
2025.2.0~rc0 N/A
2025.2.0~rc1 N/A
2025.2.1 ENABLED
% dist/cqlshutil list -gt 2025.1.0 -lt 2025.1.1
VERSION CLOUD
2025.1.0~rc0 N/A
2025.1.0~rc1 N/A
2025.1.0~rc2 N/A
2025.1.0~rc3 N/A
2025.1.0~rc4 N/A
% dist/cqlshutil download 2025.1.0 > cqlsh.tar.gz
Download completed% go test ./... -count=1 -v
=== RUN TestDownloadArchive
=== RUN TestDownloadArchive/success_2025.1.0_version_for_arm64
=== RUN TestDownloadArchive/success_2025.1.0_version_for_x86_64
=== RUN TestDownloadArchive/success_2025.2.0~rc0_version_for_arm64
=== RUN TestDownloadArchive/inexistant_2025.3.0_version_for_arm64
=== RUN TestDownloadArchive/fail_on_404_from_server
=== RUN TestDownloadArchive/fail_on_500_from_server
--- PASS: TestDownloadArchive (0.01s)
--- PASS: TestDownloadArchive/success_2025.1.0_version_for_arm64 (0.01s)
--- PASS: TestDownloadArchive/success_2025.1.0_version_for_x86_64 (0.00s)
--- PASS: TestDownloadArchive/success_2025.2.0~rc0_version_for_arm64 (0.00s)
--- PASS: TestDownloadArchive/inexistant_2025.3.0_version_for_arm64 (0.00s)
--- PASS: TestDownloadArchive/fail_on_404_from_server (0.00s)
--- PASS: TestDownloadArchive/fail_on_500_from_server (0.00s)
=== RUN TestGetDownloadPageContents
=== RUN TestGetDownloadPageContents/success_with_200_status
=== RUN TestGetDownloadPageContents/failure_with_404_status
=== RUN TestGetDownloadPageContents/failure_with_500_status
--- PASS: TestGetDownloadPageContents (0.00s)
--- PASS: TestGetDownloadPageContents/success_with_200_status (0.00s)
--- PASS: TestGetDownloadPageContents/failure_with_404_status (0.00s)
--- PASS: TestGetDownloadPageContents/failure_with_500_status (0.00s)
=== RUN TestGetScyllaVersions
=== RUN TestGetScyllaVersions/success_with_200_status
=== RUN TestGetScyllaVersions/failure_with_404_status
=== RUN TestGetScyllaVersions/failure_with_500_status
--- PASS: TestGetScyllaVersions (0.00s)
--- PASS: TestGetScyllaVersions/success_with_200_status (0.00s)
--- PASS: TestGetScyllaVersions/failure_with_404_status (0.00s)
--- PASS: TestGetScyllaVersions/failure_with_500_status (0.00s)
=== RUN TestParseDownloadedXMLContents
=== RUN TestParseDownloadedXMLContents/invalid_xml_content
=== RUN TestParseDownloadedXMLContents/valid_xml_content
--- PASS: TestParseDownloadedXMLContents (0.00s)
--- PASS: TestParseDownloadedXMLContents/invalid_xml_content (0.00s)
--- PASS: TestParseDownloadedXMLContents/valid_xml_content (0.00s)
=== RUN TestParseDownloadedJSONScyllaVersions
=== RUN TestParseDownloadedJSONScyllaVersions/invalid_json_content
=== RUN TestParseDownloadedJSONScyllaVersions/valid_json_content
--- PASS: TestParseDownloadedJSONScyllaVersions (0.00s)
--- PASS: TestParseDownloadedJSONScyllaVersions/invalid_json_content (0.00s)
--- PASS: TestParseDownloadedJSONScyllaVersions/valid_json_content (0.00s)
=== RUN TestListAllArchiveVersions
=== RUN TestListAllArchiveVersions/success
=== RUN TestListAllArchiveVersions/fail_on_404_from_server
=== RUN TestListAllArchiveVersions/fail_on_500_from_server
--- PASS: TestListAllArchiveVersions (0.00s)
--- PASS: TestListAllArchiveVersions/success (0.00s)
--- PASS: TestListAllArchiveVersions/fail_on_404_from_server (0.00s)
--- PASS: TestListAllArchiveVersions/fail_on_500_from_server (0.00s)
=== RUN TestListArchiveVersionsGreaterThan
=== RUN TestListArchiveVersionsGreaterThan/success
=== RUN TestListArchiveVersionsGreaterThan/fail_on_404_from_server
=== RUN TestListArchiveVersionsGreaterThan/fail_on_500_from_server
--- PASS: TestListArchiveVersionsGreaterThan (0.00s)
--- PASS: TestListArchiveVersionsGreaterThan/success (0.00s)
--- PASS: TestListArchiveVersionsGreaterThan/fail_on_404_from_server (0.00s)
--- PASS: TestListArchiveVersionsGreaterThan/fail_on_500_from_server (0.00s)
=== RUN TestListArchiveVersionsLesserThan
=== RUN TestListArchiveVersionsLesserThan/success
=== RUN TestListArchiveVersionsLesserThan/fail_on_404_from_server
=== RUN TestListArchiveVersionsLesserThan/fail_on_500_from_server
--- PASS: TestListArchiveVersionsLesserThan (0.00s)
--- PASS: TestListArchiveVersionsLesserThan/success (0.00s)
--- PASS: TestListArchiveVersionsLesserThan/fail_on_404_from_server (0.00s)
--- PASS: TestListArchiveVersionsLesserThan/fail_on_500_from_server (0.00s)
=== RUN TestListArchiveVersionsFromRange
=== RUN TestListArchiveVersionsFromRange/success
=== RUN TestListArchiveVersionsFromRange/fail_on_404_from_server
=== RUN TestListArchiveVersionsFromRange/fail_on_500_from_server
--- PASS: TestListArchiveVersionsFromRange (0.00s)
--- PASS: TestListArchiveVersionsFromRange/success (0.00s)
--- PASS: TestListArchiveVersionsFromRange/fail_on_404_from_server (0.00s)
--- PASS: TestListArchiveVersionsFromRange/fail_on_500_from_server (0.00s)
PASS
ok github.com/jeamon/cqlshutil/app 2.256s
=== RUN TestExecute_SuccessAppServiceCalls
=== RUN TestExecute_SuccessAppServiceCalls/missing_command
=== RUN TestExecute_SuccessAppServiceCalls/invalid_command
=== RUN TestExecute_SuccessAppServiceCalls/valid_list_command_without_arguments
=== RUN TestExecute_SuccessAppServiceCalls/valid_list_command_with_valid_less_than_flag_X
=== RUN TestExecute_SuccessAppServiceCalls/valid_list_command_with_valid_less_than_flag_X.Y
=== RUN TestExecute_SuccessAppServiceCalls/valid_list_command_with_valid_less_than_flag_X.Y.Z
=== RUN TestExecute_SuccessAppServiceCalls/valid_list_command_with_valid_less_than_flag_X.Y.Z~rcN
=== RUN TestExecute_SuccessAppServiceCalls/valid_list_command_with_invalid_less_than_flag
=== RUN TestExecute_SuccessAppServiceCalls/valid_list_command_with_valid_greater_than_flag_X
=== RUN TestExecute_SuccessAppServiceCalls/valid_list_command_with_valid_greater_than_flag_X.Y
=== RUN TestExecute_SuccessAppServiceCalls/valid_list_command_with_valid_greater_than_flag_X.Y.Z
=== RUN TestExecute_SuccessAppServiceCalls/valid_list_command_with_valid_greater_than_flag_X.Y.Z~rcN
=== RUN TestExecute_SuccessAppServiceCalls/valid_list_command_with_invalid_greater_than_flag
=== RUN TestExecute_SuccessAppServiceCalls/valid_list_command_with_valid_range_flags_X
=== RUN TestExecute_SuccessAppServiceCalls/valid_list_command_with_valid_range_flags_X.Y
=== RUN TestExecute_SuccessAppServiceCalls/valid_list_command_with_valid_range_flags_X.Y.Z
=== RUN TestExecute_SuccessAppServiceCalls/valid_list_command_with_valid_range_flags_X.Y.Z~rcN
=== RUN TestExecute_SuccessAppServiceCalls/valid_list_command_with_invalid_range_flags
=== RUN TestExecute_SuccessAppServiceCalls/valid_list_command_with_invalid_equal_range_flags
=== RUN TestExecute_SuccessAppServiceCalls/valid_list_command_with_invalid_misorder_range_flags
=== RUN TestExecute_SuccessAppServiceCalls/valid_download_command_with_valid_version_X
Download completed
=== RUN TestExecute_SuccessAppServiceCalls/valid_download_command_with_valid_version_X.Y
Download completed
=== RUN TestExecute_SuccessAppServiceCalls/valid_download_command_with_valid_version_X.Y.Z
Download completed
=== RUN TestExecute_SuccessAppServiceCalls/valid_download_command_with_valid_version_X.Y.Z~rcN
Download completed
=== RUN TestExecute_SuccessAppServiceCalls/valid_download_command_with_version
=== RUN TestExecute_SuccessAppServiceCalls/valid_download_command_without_version
=== RUN TestExecute_SuccessAppServiceCalls/valid_download_command_invalid_version
--- PASS: TestExecute_SuccessAppServiceCalls (0.00s)
--- PASS: TestExecute_SuccessAppServiceCalls/missing_command (0.00s)
--- PASS: TestExecute_SuccessAppServiceCalls/invalid_command (0.00s)
--- PASS: TestExecute_SuccessAppServiceCalls/valid_list_command_without_arguments (0.00s)
--- PASS: TestExecute_SuccessAppServiceCalls/valid_list_command_with_valid_less_than_flag_X (0.00s)
--- PASS: TestExecute_SuccessAppServiceCalls/valid_list_command_with_valid_less_than_flag_X.Y (0.00s)
--- PASS: TestExecute_SuccessAppServiceCalls/valid_list_command_with_valid_less_than_flag_X.Y.Z (0.00s)
--- PASS: TestExecute_SuccessAppServiceCalls/valid_list_command_with_valid_less_than_flag_X.Y.Z~rcN (0.00s)
--- PASS: TestExecute_SuccessAppServiceCalls/valid_list_command_with_invalid_less_than_flag (0.00s)
--- PASS: TestExecute_SuccessAppServiceCalls/valid_list_command_with_valid_greater_than_flag_X (0.00s)
--- PASS: TestExecute_SuccessAppServiceCalls/valid_list_command_with_valid_greater_than_flag_X.Y (0.00s)
--- PASS: TestExecute_SuccessAppServiceCalls/valid_list_command_with_valid_greater_than_flag_X.Y.Z (0.00s)
--- PASS: TestExecute_SuccessAppServiceCalls/valid_list_command_with_valid_greater_than_flag_X.Y.Z~rcN (0.00s)
--- PASS: TestExecute_SuccessAppServiceCalls/valid_list_command_with_invalid_greater_than_flag (0.00s)
--- PASS: TestExecute_SuccessAppServiceCalls/valid_list_command_with_valid_range_flags_X (0.00s)
--- PASS: TestExecute_SuccessAppServiceCalls/valid_list_command_with_valid_range_flags_X.Y (0.00s)
--- PASS: TestExecute_SuccessAppServiceCalls/valid_list_command_with_valid_range_flags_X.Y.Z (0.00s)
--- PASS: TestExecute_SuccessAppServiceCalls/valid_list_command_with_valid_range_flags_X.Y.Z~rcN (0.00s)
--- PASS: TestExecute_SuccessAppServiceCalls/valid_list_command_with_invalid_range_flags (0.00s)
--- PASS: TestExecute_SuccessAppServiceCalls/valid_list_command_with_invalid_equal_range_flags (0.00s)
--- PASS: TestExecute_SuccessAppServiceCalls/valid_list_command_with_invalid_misorder_range_flags (0.00s)
--- PASS: TestExecute_SuccessAppServiceCalls/valid_download_command_with_valid_version_X (0.00s)
--- PASS: TestExecute_SuccessAppServiceCalls/valid_download_command_with_valid_version_X.Y (0.00s)
--- PASS: TestExecute_SuccessAppServiceCalls/valid_download_command_with_valid_version_X.Y.Z (0.00s)
--- PASS: TestExecute_SuccessAppServiceCalls/valid_download_command_with_valid_version_X.Y.Z~rcN (0.00s)
--- PASS: TestExecute_SuccessAppServiceCalls/valid_download_command_with_version (0.00s)
--- PASS: TestExecute_SuccessAppServiceCalls/valid_download_command_without_version (0.00s)
--- PASS: TestExecute_SuccessAppServiceCalls/valid_download_command_invalid_version (0.00s)
=== RUN TestExecute_FailedAppServiceCalls
=== RUN TestExecute_FailedAppServiceCalls/missing_command
=== RUN TestExecute_FailedAppServiceCalls/invalid_command
=== RUN TestExecute_FailedAppServiceCalls/valid_list_command_without_arguments
=== RUN TestExecute_FailedAppServiceCalls/valid_list_command_with_valid_less_than_flag_X
=== RUN TestExecute_FailedAppServiceCalls/valid_list_command_with_valid_less_than_flag_X.Y
=== RUN TestExecute_FailedAppServiceCalls/valid_list_command_with_valid_less_than_flag_X.Y.Z
=== RUN TestExecute_FailedAppServiceCalls/valid_list_command_with_valid_less_than_flag_X.Y.Z~rcN
=== RUN TestExecute_FailedAppServiceCalls/valid_list_command_with_invalid_less_than_flag
=== RUN TestExecute_FailedAppServiceCalls/valid_list_command_with_valid_greater_than_flag_X
=== RUN TestExecute_FailedAppServiceCalls/valid_list_command_with_valid_greater_than_flag_X.Y
=== RUN TestExecute_FailedAppServiceCalls/valid_list_command_with_valid_greater_than_flag_X.Y.Z
=== RUN TestExecute_FailedAppServiceCalls/valid_list_command_with_valid_greater_than_flag_X.Y.Z~rcN
=== RUN TestExecute_FailedAppServiceCalls/valid_list_command_with_invalid_greater_than_flag
=== RUN TestExecute_FailedAppServiceCalls/valid_list_command_with_valid_range_flags_X
=== RUN TestExecute_FailedAppServiceCalls/valid_list_command_with_valid_range_flags_X.Y
=== RUN TestExecute_FailedAppServiceCalls/valid_list_command_with_valid_range_flags_X.Y.Z
=== RUN TestExecute_FailedAppServiceCalls/valid_list_command_with_valid_range_flags_X.Y.Z~rcN
=== RUN TestExecute_FailedAppServiceCalls/valid_list_command_with_invalid_range_flags
=== RUN TestExecute_FailedAppServiceCalls/valid_list_command_with_invalid_equal_range_flags
=== RUN TestExecute_FailedAppServiceCalls/valid_list_command_with_invalid_misorder_range_flags
=== RUN TestExecute_FailedAppServiceCalls/valid_download_command_with_valid_version_X
=== RUN TestExecute_FailedAppServiceCalls/valid_download_command_with_valid_version_X.Y
=== RUN TestExecute_FailedAppServiceCalls/valid_download_command_with_valid_version_X.Y.Z
=== RUN TestExecute_FailedAppServiceCalls/valid_download_command_with_valid_version_X.Y.Z~rcN
=== RUN TestExecute_FailedAppServiceCalls/valid_download_command_with_empty_version
=== RUN TestExecute_FailedAppServiceCalls/valid_download_command_without_version
=== RUN TestExecute_FailedAppServiceCalls/valid_download_command_invalid_version
--- PASS: TestExecute_FailedAppServiceCalls (0.00s)
--- PASS: TestExecute_FailedAppServiceCalls/missing_command (0.00s)
--- PASS: TestExecute_FailedAppServiceCalls/invalid_command (0.00s)
--- PASS: TestExecute_FailedAppServiceCalls/valid_list_command_without_arguments (0.00s)
--- PASS: TestExecute_FailedAppServiceCalls/valid_list_command_with_valid_less_than_flag_X (0.00s)
--- PASS: TestExecute_FailedAppServiceCalls/valid_list_command_with_valid_less_than_flag_X.Y (0.00s)
--- PASS: TestExecute_FailedAppServiceCalls/valid_list_command_with_valid_less_than_flag_X.Y.Z (0.00s)
--- PASS: TestExecute_FailedAppServiceCalls/valid_list_command_with_valid_less_than_flag_X.Y.Z~rcN (0.00s)
--- PASS: TestExecute_FailedAppServiceCalls/valid_list_command_with_invalid_less_than_flag (0.00s)
--- PASS: TestExecute_FailedAppServiceCalls/valid_list_command_with_valid_greater_than_flag_X (0.00s)
--- PASS: TestExecute_FailedAppServiceCalls/valid_list_command_with_valid_greater_than_flag_X.Y (0.00s)
--- PASS: TestExecute_FailedAppServiceCalls/valid_list_command_with_valid_greater_than_flag_X.Y.Z (0.00s)
--- PASS: TestExecute_FailedAppServiceCalls/valid_list_command_with_valid_greater_than_flag_X.Y.Z~rcN (0.00s)
--- PASS: TestExecute_FailedAppServiceCalls/valid_list_command_with_invalid_greater_than_flag (0.00s)
--- PASS: TestExecute_FailedAppServiceCalls/valid_list_command_with_valid_range_flags_X (0.00s)
--- PASS: TestExecute_FailedAppServiceCalls/valid_list_command_with_valid_range_flags_X.Y (0.00s)
--- PASS: TestExecute_FailedAppServiceCalls/valid_list_command_with_valid_range_flags_X.Y.Z (0.00s)
--- PASS: TestExecute_FailedAppServiceCalls/valid_list_command_with_valid_range_flags_X.Y.Z~rcN (0.00s)
--- PASS: TestExecute_FailedAppServiceCalls/valid_list_command_with_invalid_range_flags (0.00s)
--- PASS: TestExecute_FailedAppServiceCalls/valid_list_command_with_invalid_equal_range_flags (0.00s)
--- PASS: TestExecute_FailedAppServiceCalls/valid_list_command_with_invalid_misorder_range_flags (0.00s)
--- PASS: TestExecute_FailedAppServiceCalls/valid_download_command_with_valid_version_X (0.00s)
--- PASS: TestExecute_FailedAppServiceCalls/valid_download_command_with_valid_version_X.Y (0.00s)
--- PASS: TestExecute_FailedAppServiceCalls/valid_download_command_with_valid_version_X.Y.Z (0.00s)
--- PASS: TestExecute_FailedAppServiceCalls/valid_download_command_with_valid_version_X.Y.Z~rcN (0.00s)
--- PASS: TestExecute_FailedAppServiceCalls/valid_download_command_with_empty_version (0.00s)
--- PASS: TestExecute_FailedAppServiceCalls/valid_download_command_without_version (0.00s)
--- PASS: TestExecute_FailedAppServiceCalls/valid_download_command_invalid_version (0.00s)
PASS
ok github.com/jeamon/cqlshutil/cmd/cqlshutil 1.527s
? github.com/jeamon/cqlshutil/testhelpers [no test files]
Please check & read the license details
Feel free to reach out to me before any action. Feel free to connect on Twitter or linkedin