Repository: jftuga/less-Windows
Branch: master
Commit: e25a4c83c8b9
Files: 9
Total size: 13.1 KB
Directory structure:
gitextract_23kj5y12/
├── .github/
│ ├── dependabot.yml
│ └── workflows/
│ ├── comment.yml
│ └── nightly.yml
├── .gitignore
├── LICENSE
├── README.md
├── build.py
├── shared.py
└── version_compare.py
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
================================================
FILE: .github/workflows/comment.yml
================================================
on:
workflow_dispatch:
inputs:
issue_number:
required: true
owner:
required: true
repo:
required: true
body:
required: true
jobs:
comment:
runs-on: ubuntu-latest
steps:
- uses: actions/github-script@v9
with:
github-token: ${{ secrets.WINGET_TOKEN }}
script: |
github.rest.issues.createComment({
issue_number: ${{ github.event.inputs.issue_number }},
owner: '${{ github.event.inputs.owner }}',
repo: '${{ github.event.inputs.repo }}',
body: '${{ github.event.inputs.body }}'
})
================================================
FILE: .github/workflows/nightly.yml
================================================
name: nightly
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
schedule:
- cron: '0 0 * * *'
workflow_dispatch:
jobs:
checkver:
runs-on: ubuntu-latest
outputs:
new_version: ${{ steps.check_new_version.outputs.new_version }}
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
- name: Compare versions
run: python version_compare.py
- name: Check if new version exists
id: check_new_version
run: |
# If new.txt exists and is not empty
if [ -s "new.txt" ]; then
NEW_VERSION=$(cat new.txt)
echo "New version is $NEW_VERSION"
echo "new_version=$NEW_VERSION" >> $GITHUB_OUTPUT
fi
build:
runs-on: windows-${{ matrix.arch == 'arm' && '2022' || 'latest' }}
needs: checkver
if: ${{ needs.checkver.outputs.new_version }}
strategy:
matrix:
arch: [x64, x86, arm64, arm]
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
- uses: ilammy/msvc-dev-cmd@v1
with:
arch: ${{ matrix.arch != 'x64' && 'amd64_' || '' }}${{ matrix.arch }}
sdk: ${{ matrix.arch == 'arm' && '10.0.22621.0' || '' }}
- name: Build
run: python .\build.py
- name: Upload less to artifact
uses: actions/upload-artifact@v7
with:
name: less-${{ matrix.arch }}
path: |
less.exe
lesskey.exe
release:
needs: [checkver, build]
if: ${{ github.event_name != 'pull_request' }}
runs-on: ubuntu-latest
permissions:
contents: write
discussions: write
steps:
- name: Get all artifacts
uses: actions/download-artifact@v8
- name: Zip each artifact
run: find . -type d ! -path . -execdir zip -9 -rj "{}.zip" "{}" \;
- uses: octokit/request-action@v2.x
id: get_workflow_runtime
with:
route: GET /repos/{owner}/{repo}/actions/runs/{run_id}
owner: ${{ github.repository_owner }}
repo: less-Windows
run_id: ${{ github.run_id }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- id: extract_major_version
run: |
MAJOR_VERSION=$(echo ${{ needs.checkver.outputs.new_version }} | cut -d. -f1)
echo "major_version=$MAJOR_VERSION" >> $GITHUB_OUTPUT
- uses: softprops/action-gh-release@v3
with:
files: '*.zip'
body: |
Built with GitHub Actions at ${{ fromJson(steps.get_workflow_runtime.outputs.data).updated_at }}
Release notes can be found [here](http://greenwoodsoftware.com/less/news.${{ steps.extract_major_version.outputs.major_version }}.html).
tag_name: less-v${{ needs.checkver.outputs.new_version }}
discussion_category_name: Announcements
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
winget:
name: Publish to WinGet
needs: [checkver, release]
runs-on: ubuntu-latest
steps:
- uses: vedantmgoyal9/winget-releaser@main
with:
identifier: jftuga.less
version: ${{ needs.checkver.outputs.new_version }}
release-tag: less-v${{ needs.checkver.outputs.new_version }}
installers-regex: '\.zip$'
token: ${{ secrets.WINGET_TOKEN }}
================================================
FILE: .gitignore
================================================
less-*/
less*.zip
compile.bat
download.html
__pycache__/
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2020 J Taylor
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
# less-Windows [](https://github.com/jftuga/less-Windows/actions/workflows/nightly.yml)
GNU [less](https://en.wikipedia.org/wiki/Less_\(Unix\)) compiled for Windows from the [less source](http://greenwoodsoftware.com/less/) via GitHub Actions. New versions are being checked daily, and builds are compiled with the latest version of Visual Studio.
## Installation
Binaries for `less.exe` (and `lesskey.exe`) are provided on the [Releases Page](https://github.com/jftuga/less-Windows/releases). Download the appropriate one for your system. If you prefer to install less via a package manager, you can choose one of the following options:
### Winget
A new version is pushed to the upstream [winget-pkgs](https://github.com/microsoft/winget-pkgs) for every release:
```powershell
winget install jftuga.less
```
### Chocolatey
[less](https://community.chocolatey.org/packages/less) is available in the Community Repository:
```powershell
choco install less
```
### Scoop
[less](https://scoop.sh/#/apps?q=main%2Fless&s=0&d=1&o=true) is available in the Main bucket:
```powershell
scoop install less
```
================================================
FILE: build.py
================================================
#!/usr/bin/env python3
r"""
builder.py
-John Taylor
May-13-2020
Download and compile GNU less with Visual Studio
less.exe and lesskey.exe are created
"""
import os
import os.path
import shutil
import subprocess
import sys
import time
import urllib.request
import zipfile
from shared import download_less_web_page, get_latest_version_url, LESSURL
def download_and_save(url: str) -> bool:
"""Download the less .zip file and save it to the current directory
"""
# something like less-561.zip
archive = url.split("/")[-1]
if os.path.exists(archive):
sz = os.stat(archive).st_size
print("File already exists: %s with size: %d" % (archive, sz))
return archive
try:
urllib.request.urlretrieve(url, archive)
except:
return False
return archive
def extract_archive(archive: str) -> str:
"""Unzip the archive file, remove preexisting directory
"""
# given "less-561.zip", return "less-561
zip_dest = os.path.splitext(archive)[0]
if os.path.exists(zip_dest):
print("Removing preexisting directory: %s" % (zip_dest))
try:
shutil.rmtree(zip_dest)
time.sleep(1)
except:
return False
try:
with zipfile.ZipFile(archive, "r") as z:
z.extractall(".")
except:
return False
return zip_dest
def create_compile_batchfile(archive_dest: str):
"""Create a .bat file containing environment setup
and nmake compile commands
"""
bat = "compile.bat"
try:
with open(bat, "w") as fp:
fp.write("@echo off\n")
fp.write("cd %s\n" % (archive_dest))
fp.write("nmake /f Makefile.wnm\n")
fp.write("copy /y less.exe ..\n")
fp.write("copy /y lesskey.exe ..\n")
except:
return False
return bat
def main():
if not (page := download_less_web_page()):
print("Unable to download URL: %s" % (LESSURL))
sys.exit(10)
return
version, url = get_latest_version_url(page)
if version is None:
print("Unable to extract version from: %s" % (LESSURL), file=sys.stderr)
sys.exit(20)
if not (archive := download_and_save(url)):
print("Unable to download file: %s" % (url), file=sys.stderr)
sys.exit(30)
if not (archive_dest := extract_archive(archive)):
print("Unable to unzip archive: %s" % (archive), file=sys.stderr)
sys.exit(40)
if not (cmd := create_compile_batchfile(archive_dest)):
print("Unable to create batch file", file=sys.stderr)
sys.exit(50)
result = subprocess.run((cmd,), shell=True, capture_output=True)
if result.returncode > 0:
err = result.stderr.decode("utf-8")
out = result.stdout.decode("utf-8")
print("Compile failed:\n%s\n\n%s\n" % (out, err))
sys.exit(60)
if "__main__" == __name__:
main()
# end of script
================================================
FILE: shared.py
================================================
#!/usr/bin/env python3
r"""
shared.py
-John Taylor
May-14-2020
Functions shared between build.py and version_compare.py
"""
import re
import time
import urllib.request
LESSURL = "http://greenwoodsoftware.com/less/download.html"
version_url_re = re.compile(r"""Download <strong>RECOMMENDED</strong> version (.*?) """, re.M | re.S | re.I)
NEWFILE = "new.txt"
def download_less_web_page() -> str:
"""Download LESSURL and save the contents to fname
Returns:
An in-memory version of the downloaded web page
"""
fname = "download.html"
try:
urllib.request.urlretrieve(LESSURL, fname)
time.sleep(1)
except:
return False
try:
with open(fname) as fp:
page = fp.read()
except:
return False
return page
def get_latest_version_url(page: str) -> tuple:
"""Return the URL for the "RECOMMENDED version"
Args:
page: an HTML web page, provided in LESSURL
Returns:
A tuple containing: (version number, zip archive URL)
Ex: 551, http://greenwoodsoftware.com/less/less-551.zip
"""
match = version_url_re.findall(page)
if not len(match):
return (None, None)
version = match[0]
archive = "less-%s.zip" % version
url = LESSURL.replace("download.html", archive)
return version, url
================================================
FILE: version_compare.py
================================================
#!/usr/bin/env python3
r"""
version_compare.py
-John Taylor
May-14-2020
Compare local github version with less web site
"""
import json
import urllib.request
import re
import sys
from shared import download_less_web_page, get_latest_version_url, LESSURL, NEWFILE
LOCALURL = "https://api.github.com/repos/jftuga/less-Windows/releases"
def download_local_web_page() -> str:
"""Download and return JSON from LOCALURL
"""
try:
with urllib.request.urlopen(LOCALURL) as f:
page = f.read()
except:
return False
page = page.decode("utf-8")
return page
def get_latest_local_version(page: str) -> str:
"""Extract and return the lastest release version from a JSON page
Ex: 561
"""
try:
j = json.loads(page)
except:
return False
if not len(j):
return "500"
newest = j[0]
print(f'{newest["tag_name"]=}')
# The initial version is different than future versions
if "v560" == newest["tag_name"]:
return "560"
# given less-v561.17, return 561
release_version = newest["tag_name"][6:11]
if release_version.endswith(".0"):
release_version = re.sub(r"\.0$", "", release_version)
print(f'{release_version=}')
return release_version
def main():
"""Write to new.txt when a new version needs to be downloaded
"""
if not (page := download_local_web_page()):
print("Unable to download URL: %s" % (LOCALURL))
sys.exit(10)
if not (local_version := get_latest_local_version(page)):
print("Unable to extract version from URL: %s" % (LOCALURL))
sys.exit(20)
if not (page := download_less_web_page()):
print("Unable to download URL: %s" % (LESSURL))
sys.exit(30)
return
remote_version, _ = get_latest_version_url(page)
if remote_version is None:
print("Unable to extract version from: %s" % (LESSURL), file=sys.stderr)
sys.exit(40)
if remote_version == local_version:
print(f"Versions are the same: remote_version: {remote_version} local_version: {local_version}")
return
if float(local_version) >= float(remote_version):
print(f"Local version is newer: local_version: {local_version} remote_version: {remote_version}")
sys.exit(120)
print(f"Remote version is newer: remote_version: {remote_version} local_version: {local_version}")
print(f"Saving new version to file: {NEWFILE}")
try:
with open(NEWFILE, mode="w") as fp:
fp.write("%s\n" % remote_version)
except:
print(f"Unable able to open file for writing: {NEWFILE}")
sys.exit(50)
if "__main__" == __name__:
main()
gitextract_23kj5y12/ ├── .github/ │ ├── dependabot.yml │ └── workflows/ │ ├── comment.yml │ └── nightly.yml ├── .gitignore ├── LICENSE ├── README.md ├── build.py ├── shared.py └── version_compare.py
SYMBOL INDEX (9 symbols across 3 files) FILE: build.py function download_and_save (line 23) | def download_and_save(url: str) -> bool: function extract_archive (line 42) | def extract_archive(archive: str) -> str: function create_compile_batchfile (line 65) | def create_compile_batchfile(archive_dest: str): function main (line 84) | def main(): FILE: shared.py function download_less_web_page (line 20) | def download_less_web_page() -> str: function get_latest_version_url (line 43) | def get_latest_version_url(page: str) -> tuple: FILE: version_compare.py function download_local_web_page (line 20) | def download_local_web_page() -> str: function get_latest_local_version (line 33) | def get_latest_local_version(page: str) -> str: function main (line 59) | def main():
Condensed preview — 9 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (14K chars).
[
{
"path": ".github/dependabot.yml",
"chars": 125,
"preview": "version: 2\r\nupdates:\r\n - package-ecosystem: \"github-actions\"\r\n directory: \"/\"\r\n schedule:\r\n interval: \"daily"
},
{
"path": ".github/workflows/comment.yml",
"chars": 664,
"preview": "on:\n workflow_dispatch:\n inputs:\n issue_number:\n required: true\n owner:\n required: true\n "
},
{
"path": ".github/workflows/nightly.yml",
"chars": 3268,
"preview": "name: nightly\n\non:\n push:\n branches: [ master ]\n pull_request:\n branches: [ master ]\n schedule:\n - cron: '0 "
},
{
"path": ".gitignore",
"chars": 57,
"preview": "less-*/\nless*.zip\ncompile.bat\ndownload.html\n__pycache__/\n"
},
{
"path": "LICENSE",
"chars": 1065,
"preview": "MIT License\n\nCopyright (c) 2020 J Taylor\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\no"
},
{
"path": "README.md",
"chars": 1199,
"preview": "# less-Windows [](https://gith"
},
{
"path": "build.py",
"chars": 2953,
"preview": "#!/usr/bin/env python3\n\nr\"\"\"\nbuilder.py\n-John Taylor\nMay-13-2020\n\nDownload and compile GNU less with Visual Studio\nless."
},
{
"path": "shared.py",
"chars": 1342,
"preview": "#!/usr/bin/env python3\n\nr\"\"\"\nshared.py\n-John Taylor\nMay-14-2020\n\nFunctions shared between build.py and version_compare.p"
},
{
"path": "version_compare.py",
"chars": 2717,
"preview": "#!/usr/bin/env python3\n\nr\"\"\"\nversion_compare.py\n-John Taylor\nMay-14-2020\n\nCompare local github version with less web sit"
}
]
About this extraction
This page contains the full source code of the jftuga/less-Windows GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 9 files (13.1 KB), approximately 3.6k tokens, and a symbol index with 9 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.