summaryrefslogtreecommitdiffstats
path: root/scripts
diff options
context:
space:
mode:
authorClement Tsang <34804052+ClementTsang@users.noreply.github.com>2022-11-06 03:19:52 -0500
committerGitHub <noreply@github.com>2022-11-06 03:19:52 -0500
commit29bc0b67bae1598cae1fa5202dae3999c7c05f69 (patch)
tree442b80bffe1a52af2cdfdb9b6dc35506bbc107f8 /scripts
parent8c3e9669b8f2519c2479d0b241e7db129ca63ed4 (diff)
ci: rename deployment folder to scripts (#873)
Diffstat (limited to 'scripts')
-rw-r--r--scripts/cirrus/build.py182
-rw-r--r--scripts/packager.py75
-rw-r--r--scripts/windows/choco/bottom.nuspec.template57
-rw-r--r--scripts/windows/choco/choco_packager.py51
-rw-r--r--scripts/windows/choco/chocolateyinstall.ps1.template16
5 files changed, 381 insertions, 0 deletions
diff --git a/scripts/cirrus/build.py b/scripts/cirrus/build.py
new file mode 100644
index 00000000..d1d4bac1
--- /dev/null
+++ b/scripts/cirrus/build.py
@@ -0,0 +1,182 @@
+#!/bin/python3
+
+# A simple script to trigger Cirrus CI builds and download the release artifacts
+# through Cirrus CI's GraphQL interface.
+#
+# Expects the Cirrus CI API key to be set in the CIRRUS_KEY environment variable.
+
+import os
+import json
+import sys
+from textwrap import dedent
+from time import sleep, time
+from pathlib import Path
+from typing import Optional
+
+from urllib.request import Request, urlopen, urlretrieve
+
+URL = "https://api.cirrus-ci.com/graphql"
+TASKS = [
+ ("freebsd_build", "bottom_x86_64-unknown-freebsd.tar.gz"),
+ ("macos_build", "bottom_aarch64-apple-darwin.tar.gz"),
+]
+DL_URL_TEMPLATE = "https://api.cirrus-ci.com/v1/artifact/build/%s/%s/binaries/%s"
+
+
+def make_query_request(key: str, branch: str, build_type: str):
+ print("Creating query request.")
+ mutation_id = "Cirrus CI Build {}-{}-{}".format(build_type, branch, int(time()))
+ query = """
+ mutation CreateCirrusCIBuild (
+ $repo: ID!,
+ $branch: String!,
+ $mutation_id: String!
+ ) {
+ createBuild(
+ input: {
+ repositoryId: $repo,
+ branch: $branch,
+ clientMutationId: $mutation_id,
+ }
+ ) {
+ build {
+ id,
+ status
+ }
+ }
+ }
+ """
+ params = {
+ "repo": "6646638922956800",
+ "branch": branch,
+ "mutation_id": mutation_id,
+ }
+ data = {"query": dedent(query), "variables": params}
+ data = json.dumps(data).encode()
+
+ request = Request(URL, data=data, method="POST")
+ request.add_header("Authorization", "Bearer {}".format(key))
+
+ return request
+
+
+def check_build_status(key: str, id: str) -> Optional[str]:
+ query = """
+ query BuildStatus($id: ID!) {
+ build(id: $id) {
+ status
+ }
+ }
+ """
+ params = {
+ "id": id,
+ }
+
+ data = {"query": dedent(query), "variables": params}
+ data = json.dumps(data).encode()
+
+ request = Request(URL, data=data, method="POST")
+ request.add_header("Authorization", "Bearer {}".format(key))
+ with urlopen(request) as response:
+ response = json.load(response)
+ if response.get("errors") is not None:
+ print("There was an error in the returned response.")
+ return None
+
+ try:
+ status = response["data"]["build"]["status"]
+ return status
+ except KeyError:
+ print("There was an issue with creating a build job.")
+ return None
+
+
+def try_download(build_id: str, dl_path: Path):
+ for (task, file) in TASKS:
+ url = DL_URL_TEMPLATE % (build_id, task, file)
+ out = dl_path / file
+ print("Downloading {} to {}".format(file, out))
+ urlretrieve(url, out)
+
+
+def main():
+ args = sys.argv
+ env = os.environ
+
+ key = env["CIRRUS_KEY"]
+ branch = args[1]
+ dl_path = args[2] if len(args) >= 3 else ""
+ dl_path = Path(dl_path)
+ build_type = args[3] if len(args) >= 4 else "build"
+ build_id = args[4] if len(args) >= 5 else None
+
+ # Check if this build has already been completed before.
+ if build_id is not None:
+ print("Previous build ID was provided, checking if complete.")
+ status = check_build_status(key, build_id)
+ if status.startswith("COMPLETE"):
+ print("Starting download of previous build ID")
+ try_download(build_id, dl_path)
+ else:
+ # Try up to three times
+ MAX_ATTEMPTS = 3
+ success = False
+
+ for i in range(MAX_ATTEMPTS):
+ if success:
+ break
+ print("Attempt {}:".format(i + 1))
+
+ with urlopen(make_query_request(key, branch, build_type)) as response:
+ response = json.load(response)
+
+ if response.get("errors") is not None:
+ print("There was an error in the returned response.")
+ continue
+
+ try:
+ build_id = response["data"]["createBuild"]["build"]["id"]
+ print("Created build job {}.".format(build_id))
+ except KeyError:
+ print("There was an issue with creating a build job.")
+ continue
+
+ # First, sleep 4 minutes, as it's unlikely it'll finish before then.
+ SLEEP_MINUTES = 4
+ print("Sleeping for {} minutes.".format(SLEEP_MINUTES))
+ sleep(60 * SLEEP_MINUTES)
+ print("Mandatory nap over. Starting to check for completion.")
+
+ MINUTES = 10
+ SLEEP_SEC = 30
+ TRIES = int(MINUTES * (60 / SLEEP_SEC)) # Works out to 20 tries.
+
+ for attempt in range(TRIES):
+ print("Checking...")
+ status = check_build_status(key, build_id)
+ if status.startswith("COMPLETE"):
+ print("Build complete. Downloading artifact files.")
+ sleep(5)
+ try_download(build_id, dl_path)
+ success = True
+ break
+ else:
+ print("Build status: {}".format(status or "unknown"))
+ if status == "ABORTED":
+ print("Build aborted, bailing.")
+ break
+ elif status.lower().startswith("fail"):
+ print("Build failed, bailing.")
+ break
+ elif attempt + 1 < TRIES:
+ sleep(SLEEP_SEC)
+ else:
+ print("Build failed to complete after {} minutes, bailing.".format(MINUTES))
+ continue
+
+ if not success:
+ exit(2)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/scripts/packager.py b/scripts/packager.py
new file mode 100644
index 00000000..30f56182
--- /dev/null
+++ b/scripts/packager.py
@@ -0,0 +1,75 @@
+import hashlib
+import sys
+from string import Template
+
+args = sys.argv
+version = args[1]
+template_file_path = args[2]
+generated_file_path = args[3]
+
+# SHA512, SHA256, or SHA1
+hash_type = args[4]
+
+# Deployment files
+deployment_file_path_1 = args[5]
+deployment_file_path_2 = args[6] if len(args) > 6 else None
+deployment_file_path_3 = args[7] if len(args) > 7 else None
+
+print("Generating package for file: %s" % deployment_file_path_1)
+if deployment_file_path_2 is not None:
+ print("and for file: %s" % deployment_file_path_2)
+if deployment_file_path_3 is not None:
+ print("and for file: %s" % deployment_file_path_3)
+print(" VERSION: %s" % version)
+print(" TEMPLATE PATH: %s" % template_file_path)
+print(" SAVING AT: %s" % generated_file_path)
+print(" USING HASH TYPE: %s" % hash_type)
+
+
+def get_hash(deployment_file):
+ if str.lower(hash_type) == "sha512":
+ deployment_hash = hashlib.sha512(deployment_file.read()).hexdigest()
+ elif str.lower(hash_type) == "sha256":
+ deployment_hash = hashlib.sha256(deployment_file.read()).hexdigest()
+ elif str.lower(hash_type) == "sha1":
+ deployment_hash = hashlib.sha1(deployment_file.read()).hexdigest()
+ else:
+ print('Unsupported hash format "%s". Please use SHA512, SHA256, or SHA1.', hash_type)
+ exit(1)
+
+ print("Generated hash: %s" % str(deployment_hash))
+ return deployment_hash
+
+
+with open(deployment_file_path_1, "rb") as deployment_file_1:
+ deployment_hash_1 = get_hash(deployment_file_1)
+
+ deployment_hash_2 = None
+ if deployment_file_path_2 is not None:
+ with open(deployment_file_path_2, "rb") as deployment_file_2:
+ deployment_hash_2 = get_hash(deployment_file_2)
+
+ deployment_hash_3 = None
+ if deployment_file_path_3 is not None:
+ with open(deployment_file_path_3, "rb") as deployment_file_3:
+ deployment_hash_3 = get_hash(deployment_file_3)
+
+ with open(template_file_path, "r") as template_file:
+ template = Template(template_file.read())
+
+ substitutes = dict()
+ substitutes["version"] = version
+ substitutes["hash1"] = deployment_hash_1
+ if deployment_hash_2 is not None:
+ substitutes["hash2"] = deployment_hash_2
+ if deployment_hash_3 is not None:
+ substitutes["hash3"] = deployment_hash_3
+
+ substitute = template.safe_substitute(substitutes)
+
+ print("\n================== Generated package file ==================\n")
+ print(substitute)
+ print("\n============================================================\n")
+
+ with open(generated_file_path, "w") as generated_file:
+ generated_file.write(substitute)
diff --git a/scripts/windows/choco/bottom.nuspec.template b/scripts/windows/choco/bottom.nuspec.template
new file mode 100644
index 00000000..7d176f4e
--- /dev/null
+++ b/scripts/windows/choco/bottom.nuspec.template
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Read this before creating packages: https://chocolatey.org/docs/create-packages -->
+<!-- It is especially important to read the above link to understand additional requirements when publishing packages to the community feed aka dot org (https://chocolatey.org/packages). -->
+
+<!-- Test your packages in a test environment: https://github.com/chocolatey/chocolatey-test-environment -->
+
+<!--
+This is a nuspec. It mostly adheres to https://docs.nuget.org/create/Nuspec-Reference. Chocolatey uses a special version of NuGet.Core that allows us to do more than was initially possible. As such there are certain things to be aware of:
+
+* the package xmlns schema url may cause issues with nuget.exe
+* Any of the following elements can ONLY be used by choco tools - projectSourceUrl, docsUrl, mailingListUrl, bugTrackerUrl, packageSourceUrl, provides, conflicts, replaces
+* nuget.exe can still install packages with those elements but they are ignored. Any authoring tools or commands will error on those elements
+-->
+
+<!-- You can embed software files directly into packages, as long as you are not bound by distribution rights. -->
+<!-- * If you are an organization making private packages, you probably have no issues here -->
+<!-- * If you are releasing to the community feed, you need to consider distribution rights. -->
+<!-- Do not remove this test for UTF-8: if “Ω” doesn’t appear as greek uppercase omega letter enclosed in quotation marks, you should use an editor that supports UTF-8, not this one. -->
+<package xmlns="http://schemas.microsoft.com/packaging/2015/06/nuspec.xsd">
+ <metadata>
+ <!-- == PACKAGE SPECIFIC SECTION == -->
+ <id>bottom</id>
+ <version>$version</version>
+
+ <!-- == SOFTWARE SPECIFIC SECTION == -->
+ <!-- This section is about the software itself -->
+ <title>bottom</title>
+ <authors>Clement Tsang</authors>
+ <projectUrl>https://github.com/ClementTsang/bottom</projectUrl>
+ <licenseUrl>https://github.com/ClementTsang/bottom/blob/master/LICENSE</licenseUrl>
+ <requireLicenseAcceptance>true</requireLicenseAcceptance>
+ <projectSourceUrl>https://github.com/ClementTsang/bottom</projectSourceUrl>
+ <packageSourceUrl>https://github.com/ClementTsang/choco-bottom</packageSourceUrl>
+ <docsUrl>https://clementtsang.github.io/bottom/stable</docsUrl>
+ <bugTrackerUrl>https://github.com/ClementTsang/bottom/issues</bugTrackerUrl>
+ <tags>cli cross-platform terminal top tui monitoring bottom btm</tags>
+ <summary>A customizable cross-platform graphical process/system monitor for the terminal.</summary>
+ <description>
+ A customizable cross-platform graphical process/system monitor for the terminal. Supports Linux, macOS, and Windows. Inspired by [gtop](https://github.com/aksakalli/gtop), [gotop](https://github.com/xxxserxxx/gotop) and [htop](https://github.com/htop-dev/htop).
+
+ **Usage**
+ To use, run `btm` in a terminal.
+
+ For more [documentation and usage](https://github.com/ClementTsang/bottom/blob/master/README.md), see the [official repo](https://github.com/ClementTsang/bottom).
+
+
+ **Note**
+ This currently depends on Visual C++ Redistributable for Visual Studio 2015 https://chocolatey.org/packages/vcredist2015.
+ </description>
+ <releaseNotes>https://github.com/ClementTsang/bottom/releases/tag/$version/</releaseNotes>
+ </metadata>
+ <files>
+ <!-- this section controls what actually gets packaged into the Chocolatey package -->
+ <file src="tools\**" target="tools" />
+ <!--Building from Linux? You may need this instead: <file src="tools/**" target="tools" />-->
+ </files>
+</package>
diff --git a/scripts/windows/choco/choco_packager.py b/scripts/windows/choco/choco_packager.py
new file mode 100644
index 00000000..daf3f15f
--- /dev/null
+++ b/scripts/windows/choco/choco_packager.py
@@ -0,0 +1,51 @@
+# Because choco is a special case and I'm too lazy to make my
+# packaging script robust enough, so whatever, hard-code time.
+
+import hashlib
+import sys
+from string import Template
+import os
+
+args = sys.argv
+deployment_file_path_64 = args[1]
+version = args[2]
+nuspec_template = args[3]
+ps1_template = args[4]
+generated_nuspec = args[5]
+generated_ps1 = args[6]
+generated_ps1_dir = args[7]
+
+print("Generating Chocolatey package for:")
+print(" 64-bit: %s" % deployment_file_path_64)
+print(" VERSION: %s" % version)
+print(" NUSPEC TEMPLATE: %s" % nuspec_template)
+print(" PS1 TEMPLATE: %s" % ps1_template)
+print(" GENERATED NUSPEC: %s" % generated_nuspec)
+print(" GENERATED PS1: %s" % generated_ps1)
+print(" GENERATED PS1 DIR: %s" % generated_ps1_dir)
+
+with open(deployment_file_path_64, "rb") as deployment_file_64:
+ hash_64 = hashlib.sha1(deployment_file_64.read()).hexdigest()
+
+ print("Generated hash for 64-bit program: %s" % str(hash_64))
+
+ with open(nuspec_template, "r") as template_file:
+ template = Template(template_file.read())
+ substitute = template.safe_substitute(version=version)
+ print("\n================== Generated nuspec file ==================\n")
+ print(substitute)
+ print("\n============================================================\n")
+
+ with open(generated_nuspec, "w") as generated_file:
+ generated_file.write(substitute)
+
+ os.makedirs(generated_ps1_dir)
+ with open(ps1_template, "r") as template_file:
+ template = Template(template_file.read())
+ substitute = template.safe_substitute(version=version, hash_64=hash_64)
+ print("\n================== Generated chocolatey-install file ==================\n")
+ print(substitute)
+ print("\n============================================================\n")
+
+ with open(generated_ps1, "w") as generated_file:
+ generated_file.write(substitute)
diff --git a/scripts/windows/choco/chocolateyinstall.ps1.template b/scripts/windows/choco/chocolateyinstall.ps1.template
new file mode 100644
index 00000000..a9245d18
--- /dev/null
+++ b/scripts/windows/choco/chocolateyinstall.ps1.template
@@ -0,0 +1,16 @@
+$ErrorActionPreference = 'Stop';
+$toolsDir = "$(Split-Path -parent $MyInvocation.MyCommand.Definition)"
+$url = 'https://github.com/ClementTsang/bottom/releases/download/$version/bottom_x86_64-pc-windows-msvc.zip'
+
+$packageArgs = @{
+ packageName = $env:ChocolateyPackageName
+ softwareName = 'bottom'
+ unzipLocation = $toolsDir
+ fileType = 'exe'
+ url = $url
+ checksum = '$hash_64'
+ checksumType = 'sha1'
+
+}
+Install-ChocolateyZipPackage @packageArgs
+j \ No newline at end of file