{"id":22184228,"url":"https://github.com/dragondive/whistle","last_synced_at":"2026-05-04T00:31:05.904Z","repository":{"id":259233769,"uuid":"846510933","full_name":"dragondive/whistle","owner":"dragondive","description":"whistle is a utility to automatically download Ubuntu WSL images, create new WSL2 instances and provision them.","archived":false,"fork":false,"pushed_at":"2025-10-06T06:18:09.000Z","size":48,"stargazers_count":2,"open_issues_count":2,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-04-25T16:03:46.406Z","etag":null,"topics":["automation","bash-script","powershell-script","sysadmin-scripts","windows","wsl","wsl2"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dragondive.png","metadata":{"files":{"readme":"README.rst","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"dragondive","custom":"upi://pay?pa=apai@upi\u0026pn=Aravind%20%20Pai\u0026cu=INR\u0026mode=02\u0026purpose=00\u0026orgid=189999\u0026sign=1pB+zZ+Dp+6ACZlEhfuzNf90Guvoh6QoE/0zlgetfhcN65/L6BULimTDkH5gPm2roKSh62NDYcLAXLlUA8zQPZpy6sOqpfVeyklufuWsE2cA7bGR4l8whufvlgC8p4v66UZB7IuCKIlfgcOuMpYSY1kRI+EEuN5DLaiQyjpd/bI="}},"created_at":"2024-08-23T11:13:49.000Z","updated_at":"2025-11-19T03:59:55.000Z","dependencies_parsed_at":"2025-09-07T16:43:51.971Z","dependency_job_id":"8fa3fd0f-0d77-47a5-8d03-5ad8f6b0671f","html_url":"https://github.com/dragondive/whistle","commit_stats":null,"previous_names":["dragondive/whistle"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/dragondive/whistle","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dragondive%2Fwhistle","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dragondive%2Fwhistle/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dragondive%2Fwhistle/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dragondive%2Fwhistle/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dragondive","download_url":"https://codeload.github.com/dragondive/whistle/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dragondive%2Fwhistle/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32590079,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-03T22:12:39.696Z","status":"ssl_error","status_checked_at":"2026-05-03T22:09:10.534Z","response_time":103,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["automation","bash-script","powershell-script","sysadmin-scripts","windows","wsl","wsl2"],"created_at":"2024-12-02T10:12:12.183Z","updated_at":"2026-05-04T00:31:05.892Z","avatar_url":"https://github.com/dragondive.png","language":"Shell","funding_links":["https://github.com/sponsors/dragondive","upi://pay?pa=apai@upi\u0026pn=Aravind%20%20Pai\u0026cu=INR\u0026mode=02\u0026purpose=00\u0026orgid=189999\u0026sign=1pB+zZ+Dp+6ACZlEhfuzNf90Guvoh6QoE/0zlgetfhcN65/L6BULimTDkH5gPm2roKSh62NDYcLAXLlUA8zQPZpy6sOqpfVeyklufuWsE2cA7bGR4l8whufvlgC8p4v66UZB7IuCKIlfgcOuMpYSY1kRI+EEuN5DLaiQyjpd/bI=","https://buymeacoffee.com/dragondive"],"categories":[],"sub_categories":[],"readme":"Whistle\n=======\n\n``whistle`` is a utility to automatically download Ubuntu WSL images, create new WSL2\ninstances and provision them.\n\n.. contents:: **Outline**\n\nHow to use\n----------\n\n.. pull-quote:: \\:one: **ONE-TIME SETUP**\n\n   1. Install WSL with the below command\n\n   .. code-block:: terminal\n\n      wsl --install --no-distribution\n\n   2. Restart your computer.\n\n1. Download this repository as a zip file and extract it to any directory on your Windows machine.\n2. Open a powershell terminal and navigate to that directory.\n\n.. pull-quote:: \\:bulb: **TIP**\n\n   Run the below command to read the help message. Determine the setup bundles you want to install\n   on the new WSL2 instance and any other customizations you want to make.\n\n   .. code-block:: powershell\n\n      PowerShell -ExecutionPolicy Bypass -File .\\whistle.ps1 -Help\n\n3. Run the following command:\n\n   .. code-block:: powershell\n\n      PowerShell -ExecutionPolicy Bypass -File .\\whistle.ps1\n\n   This creates a new WSL2 instance of the default Linux flavour and release, with the default\n   instance name and only the core setup bundles installed. See the `Parameters`_ section below to\n   provision your WSL2 instance with additional setup bundles and for other customizations.\n\n   .. pull-quote:: \\:bangbang: **IMPORTANT**\n\n      The script also creates a standard user on the WSL2 instance. By default, the\n      username and password are the same as the instance name.\n\n   .. pull-quote:: \\:bulb: **TIP**\n\n      To create another instance, run the command again with a different instance name.\n\n   .. pull-quote:: \\:drum: **ATTENTION**\n\n      PowerShell's `execution policy \u003chttps://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_execution_policies\u003e`_\n      prevents execution of unsigned scripts. The ``-ExecutionPolicy Bypass`` in the\n      above command bypasses it to enable ``whistle.ps1`` to be executed. I do not\n      currently want to buy a code-signing certificate. However, I will easily change\n      my mind if I receive enough sponsorship. See the `Sponsoring`_ section for\n      sponsoring information.\n\nParameters\n----------\n\n.. list-table:: Parameters\n   :header-rows: 1\n\n   * - **⠀⠀⠀Parameter⠀⠀⠀**\n     - **Description**\n     - **Examples**\n     - **Default**\n     - **Notes**\n   * - ``-WslDistroName``\n     - Name for your new WSL2 instance.\n     - ``whistleblower``, ``heavens-arena``\n     - ``whistleblower``\n     -\n   * - ``-ReleaseName``\n     - Ubuntu release name.\n     - ``noble``, ``jammy``\n     - ``noble``\n     - Available releases at https://cloud-images.ubuntu.com/wsl/.\n   * - ``-ReleaseTag``\n     - Release tag of the WSL2 image to download.\n     - ``current``, ``20241008``\n     - ``current``\n     - Available tags inside the chosen release directory at the above page.\n   * - ``-ReleaseArch``\n     - Architecture of the WSL2 image.\n     - ``amd64``, ``arm64``\n     - ``amd64``\n     -\n   * - ``-SetupArgs``\n     - Arguments for the setup script ``whistle.bash``.\n     - ``\"-h\"``, ``\"-b python3\"``, ``\"-u dragondive -b copy-ssh-keys,rust\"``\n     - ``\"\"``\n     - The argument string to ``-SetupArgs`` needs to be enclosed in double quotes.\n   * - ``-Help``\n     - Display information on how to use ``whistle`` to create and provision a new WSL2 instance.\n     -\n     -\n     - Use this information to determine the setup bundles you want to install and any other\n       customizations you want to make.\n\n\nContributor Documentation\n-------------------------\n\n``whistle`` consists of two scripts:\n\n1. The powershell script ``whistle.ps1`` that downloads the WSL2 image and creates an\n   instance of it.\n2. The bash script ``whistle.bash`` that provisions the installed WSL2 instance.\n\nThese scripts are further described in the below sections.\n\npowershell script ``whistle.ps1``\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThis script performs the following main operations:\n\n1. Download the user-specified WSL2 image: As an optimization, the images are cached to\n   a standard location which avoids redownloading when the script is run multiple times.\n2. Import the WSL2 image to create a new instance of it.\n3. Install VS Code: It is more convenient to install it on Windows and further configure\n   it from WSL2 than installing it directly inside WSL2.\n4. Run the provisioning script ``whistle.bash`` inside the newly created WSL2 instance.\n\nbash script ``whistle.bash``\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThis script performs various installation and configuration steps. It first executes as\nthe root user and then as a standard user. While running as the root user, it also\ncreates the standard user.\n\nThe installation and configuration steps are organized into setup bundles. Setup bundles\nare of two types:\n\n1. **core bundles**: These are always executed as they perform essential installation\n   and configuration.\n2. **optional bundles**: These are executed only if requested.\n\nHow to define a new setup bundle\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThis section describes the steps required to define a new setup bundle, which is given\nthe hypothetical name ``watchdog`` for clarity of understanding. Perform the following\nmodifications in the ``whistle.bash`` file:\n\n1. Decide if ``watchdog`` is a core bundle or an optional bundle. Accordingly, add an\n   item to the ``EXECUTE_BUNDLE`` associative array.\n\n   *Core bundle*\n\n   .. code-block:: bash\n      :caption: watchdog is a core bundle\n\n      EXECUTE_BUNDLE=(\n      ...\n          [watchdog]=1\n      )\n\n   *Optional bundle*\n\n   .. code-block:: bash\n      :caption: watchdog is an optional bundle\n\n      EXECUTE_BUNDLE=(\n      ...\n          [watchdog]=0\n      )\n\n2. Determine if the ``watchdog`` bundle should be executed as the root user or as\n   the standard user. This determines the placement of its installation and\n   configuration steps block (described in the next step). You may also execute it in\n   two parts, first as the root user and then as the standard user.\n\n   * To execute it as the root user, the installation and configuration block needs to\n     be inside the following ``if`` ... ``fi`` block:\n\n     .. code-block:: bash\n        :caption: Execute watchdog as the root user\n\n        if [[ $EUID -eq 0 ]]; then\n        ...\n        # watchdog's installation and configuration block (described in the next step)\n        # needs to go here.\n        ...\n        fi\n\n   * To execute it as the standard user, the installation and configuration block needs\n     to be outside *and* after the above-mentioned ``if`` ... ``fi`` block.\n\n     .. pull-quote:: \\:bulb: **TIP**\n\n        To preserve any environment variables when the script switches from the root\n        user to the standard user, append it to the ``--preserve-env`` argument of the\n        ``exec sudo`` command:\n\n        .. code-block:: bash\n           :caption: preserving environment variables when switching to the standard user\n           :highlight-lines: 2\n\n           echo \"Switching to the standard user for further configuration...\"\n           exec sudo \\\n           --preserve-env=USERNAME,PATH,WSL_DISTRO_NAME \\\n           --login \\\n           --user \"$DEFAULT_USER\" \\\n           \"$(realpath $0)\" \"${ARGUMENTS[@]}\"\n\n3. Define the installation and configuration steps for ``watchdog`` in\n   an ``if`` ... ``fi`` block:\n\n   .. code-block:: bash\n      :caption: installation and configuration steps for the watchdog bundle\n\n      if [ \"${EXECUTE_BUNDLE[watchdog]}\" -eq 1 ]; then\n          echo \"Installing watchdog...\"\n\n          # Add installation and configuration steps for watchdog here\n          sudo apt-get install -yq example-watchdog\n          export PATH=\"$PATH:/usr/bin/example-watchdog\" | tee -a /home/$DEFAULT_USER/.profile\n          ...\n      fi\n\n   * **VS Code extensions** (optional): Suitable VS Code extensions may be\n     specified for installation in the installation and configuration block:\n\n     .. code-block:: bash\n        :caption: Specifying VS Code extensions\n\n        VSCODE_EXTENSIONS+=(\\\n            \"whistleblower.watchdog.bark\", \\\n            \"whistleblower.watchdog.bite\" \\\n        )\n\n4. Update the ``display_help()`` function mentioning the ``watchdog`` setup bundle,\n   with additional explanation if necessary.\n\nSponsoring\n----------\n\nIf you like ``whistle`` and you are doing well in life, you can sponsor it. You can\nmake a recurring or a one-time contribution with any amount of your choice. My finances\nare thankfully in a reasonably healthy state, so the sponsorship is for you to feel\ngood about supporting what you found useful.\n\n.. pull-quote:: \\:pray: **CREDIT**\n\n   The text of the above message is inspired by `agadmator's Excellent Subscribers video \u003chttps://youtu.be/wlPl__FzaTI?si=hVwbV0tAUwyWMpTF\u003e`_.\n\n**Sponsoring options**\n\nSponsor using one of the following options:\n\n.. raw:: html\n\n   \u003ca href=\"https://github.com/sponsors/dragondive\"\u003e\u003cimg src=\"https://img.shields.io/badge/Github-%E2%9E%9C-black?style=for-the-badge\u0026logo=github\" alt=\"Github - ➜\"\u003e\u003c/a\u003e\n   \u003cbr\u003e\n   \u003ca href=\"https://buymeacoffee.com/dragondive\"\u003e\u003cimg src=\"https://img.shields.io/badge/Buy_me_a_coffee-%E2%9E%9C-black?style=for-the-badge\u0026logo=buymeacoffee\" alt=\"Buy me a coffee - ➜\"\u003e\u003c/a\u003e\n\n|\n\nYou can also sponsor directly with Unified Payments Interface (UPI) :fire:, if you are\nIndian :india: or in a country that supports remittance by UPI to India. Scan the below\nQR code or use my UPI id ``apai@upi``.\n\n.. raw:: html\n\n   \u003cdiv align=\"center\"\u003e\n      \u003ca href=\"upi://pay?pa=apai@upi\u0026pn=Aravind%20%20Pai\u0026cu=INR\u0026mode=02\u0026purpose=00\u0026orgid=189999\u0026sign=1pB+zZ+Dp+6ACZlEhfuzNf90Guvoh6QoE/0zlgetfhcN65/L6BULimTDkH5gPm2roKSh62NDYcLAXLlUA8zQPZpy6sOqpfVeyklufuWsE2cA7bGR4l8whufvlgC8p4v66UZB7IuCKIlfgcOuMpYSY1kRI+EEuN5DLaiQyjpd/bI=\"\u003e\n         \u003cimg src=\"https://raw.githubusercontent.com/dragondive/.github/refs/heads/main/apai_upi_qrcode.jpg\" alt=\"upi://pay?pa=apai@upi\u0026pn=Aravind%20%20Pai\u0026cu=INR\u0026mode=02\u0026purpose=00\u0026orgid=189999\u0026sign=1pB+zZ+Dp+6ACZlEhfuzNf90Guvoh6QoE/0zlgetfhcN65/L6BULimTDkH5gPm2roKSh62NDYcLAXLlUA8zQPZpy6sOqpfVeyklufuWsE2cA7bGR4l8whufvlgC8p4v66UZB7IuCKIlfgcOuMpYSY1kRI+EEuN5DLaiQyjpd/bI=\" title=\"sponsor dragondive\" width=\"200\"\u003e\n      \u003c/a\u003e\n   \u003c/div\u003e\n\nFrequently Asked Questions\n--------------------------\n\n.. pull-quote:: \\:question: **Question**\n\n   Why doesn't ``whistle`` have a setup bundle for *\u003ca language or technology that\n   I use or prefer\u003e*?\n\n.. pull-quote:: \\:speech_balloon: **Answer**\n\n   The current ``whistle`` is a minimal working utility. I released it so that it\n   grows with developer community's contributions. You are welcome to contribute more\n   setup bundles. Refer `Contributor Documentation`_ for more information. I also plan\n   to add more setup bundles in the future.\n\n|\n\n.. pull-quote:: \\:question: **Question**\n\n   Can the *X* setup bundle include tool *Y* or exclude tool *Z* because that's my\n   team's setup at work?\n\n.. pull-quote:: \\:speech_balloon: **Answer**\n\n   Sure! You may modify any setup bundle in ``whistle.bash`` to suit your preference.\n   Please consider contributing your changes back to ``whistle`` if it would be useful\n   to other developers.\n\n|\n\n.. pull-quote:: \\:question: **Question**\n\n   I don't like VS Code, I prefer using the *X* IDE instead. Why does ``whistle`` force\n   me to use VS Code?\n\n.. pull-quote:: \\:speech_balloon: **Answer**\n\n   You are not forced to use VS Code. You can modify the ``whistle`` script to install\n   and configure your preferred IDE. You can even get rid of the VS Code setup.\n\n   ``whistle`` started as my personal utility project. I regularly use many programming\n   languages, such as Python, Java, C++, Rust and Go. I also frequently write scripts\n   in bash and powershell. Besides, I routinely work with multiple markup and\n   configuration formats, such as Markdown, RST, CSV, TOML, YAML, INI and JSON.\n   A general-purpose IDE is more convenient even if it lacks some features of the\n   language-specific IDEs.\n\n   VS Code works seamlessly with minimal hassles on Windows, WSL2 running on Windows,\n   *and* docker containers running inside that WSL2. Other IDEs have not offered me a\n   smooth experience in this area.\n\n|\n\n.. pull-quote:: \\:question: **Question**\n\n   Can I use ``whistle`` to install the *X* flavour of Linux instead of Ubuntu?\n\n.. pull-quote:: \\:speech_balloon: **Answer**\n\n   Yes, certainly. You are free to enhance ``whistle`` to make the Linux flavour\n   configurable. Please consider contributing your enhancement back to the community\n   as well.\n\n|\n\n.. pull-quote:: \\:question: **Question**\n\n   Why do you want the user to modify your code to get it working for them? Isn't that\n   a poor design or even an anti-pattern?\n\n.. pull-quote:: \\:speech_balloon: **Answer**\n\n   For any general-purpose utliity, that would indeed be a poor design. However,\n   ``whistle`` is meant primarily for developers. Developers are expected to be able to\n   adapt a powershell and a bash script, even with no prior scripting experience, so I do\n   consider this a problem.\n\n   Moreover, it is not practical to create a configuration script that fits everyone's\n   needs exactly. However, if there is sufficient interest from the community, I would\n   consider refactoring to configure the setup bundles through a YAML or TOML\n   configuration file.\n\n|\n\n.. pull-quote:: \\:question: **Question**\n\n   Why do you consider docker to be a core bundle?\n\n.. pull-quote:: \\:speech_balloon: **Answer**\n\n   Docker is the most commonly used containerization technology. Personally, I strongly\n   prefer using tools through their docker container instead of the local installation.\n   Local installation often leads to mess and clutter, along with the occasional\n   dependency hells. Moreover, trying out and comparing various versions of tools is a\n   breeze with docker.\n\n|\n\n.. pull-quote:: \\:question: **Question**\n\n   What was your motivation to create ``whistle``?\n\n.. pull-quote:: \\:speech_balloon: **Answer**\n\n   We humans have created many great things in this world. We have also created the\n   Windows operating system, which many developers end up using instead of Linux.\n   This has also led to the creation of the Windows Subsystem for Linux (WSL).\n\n   The `standard approach \u003chttps://learn.microsoft.com/en-us/windows/wsl/install\u003e`_ of\n   installing only one instance of a WSL release was highly limiting for a lot of my\n   development work. I discovered the lesser known option of importing a WSL image,\n   which could be used to create multiple instances. However, that still requires some\n   configuration to be usable. There were also several steps I performed repeatedly to\n   setup my WSL instances. The logical next step was to automate.\n\n   Having enjoyed the flexibility of multiple WSL instances—created with a single\n   command line invocation—and saving hundreds of hours in the process, I decided to\n   share my work with the developer community, for the benefit of developers who need\n   to use Windows.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdragondive%2Fwhistle","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdragondive%2Fwhistle","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdragondive%2Fwhistle/lists"}