Auto-Update.ahk - Self-Updating Solution for Releasing Public AHKv2 Applications

Post your working scripts, libraries and tools.
sashaatx
Posts: 333
Joined: 27 May 2021, 08:27
Contact:

Auto-Update.ahk - Self-Updating Solution for Releasing Public AHKv2 Applications

Post by sashaatx » 25 Mar 2023, 16:33

This library is an extension of my GitHub repository update, which explores AHKv2 with credit to Json Native.ahk creator viewtopic.php?t=100602

For exe's, zip files, any sort of autohotkey release. Provide a path, a github repo, and this solution will store version data automatically. When the release on github get's an update, the user will be prompted to download the update upon function call. It will download, unzip, and overwrite. Ensuring users have the latest release of your app.


You can find the repository at https://github.com/samfisherirl/Auto-Update.ahk-AHK-v2-easily-update-ahk-apps-remotely
If you like, drop a star for an up and coming developer
As small problems crop up and get fixed, the github will contain the updates

This solution performs the following tasks:

-Receives configuration information for an application (public releases) that requires remote updates, using "github.ahk" as an example.
-Connects to Github's API to retrieve release tag (version), release download URL, and release updates.
-Stores version data in a local JSON log file.
-Every time the function calls are made, the JSON file is imported, and Github API redownloads the latest version data.
-If the version does not match the local version, a download prompt appears (customizable).
-For Zip, Rar, 7z file types, 7zip command-line utility extracts the release and overwrites the existing application path set by the user.
-For Exe, a simple file move operation occurs.
-Version data is saved for future use.

Please note that although this solution works, it may have one or two errors in various use cases, Ill throw it in the VM now. If you report any issues, I will fix them as soon as possible.

It is important to implement Try and Catch as a code feature (I do not update self-referentially, so be sure to check the GitHub for updates).

For now, releases must be in the zip's main directory. I do not have a function to handle zips with the main app in a folder.




Code: Select all

; this is example.ahk
#Include %A_ScriptDir%\64bit\Native.ahk
#Include %A_ScriptDir%\64bit\github.ahk
#Include %A_ScriptDir%\64bit\auto_update.ahk
;get all needed files here https://github.com/samfisherirl/Auto-Update.ahk-AHK-v2-easily-update-ahk-apps-remotely

/*
This solution does the following:
- Takes settings for an app (likely for public release) that needs remote updates, ill use "github.ahk" as an example.
- Github's API returns release Tag (version), download url, and release updates
- Library connects to the github API and stores version data in a local json temp file
- Everytime the function calls are made in the example the json files is imported and github API redownloads the latest version data
- If version doesn't match local version, a download prompt is offered (customizable)
- 7zip command line utility invokes extraction of the release and overwrites the existing application path set by the user
- Version data is stored for future use

 keep in mind this works but may have an error or two upon various use cases and if reported, I will fix asap.

Try, Catch need to be implimented as a code feature (I dont self-referentially update for you so make sure to check the github  for updates ;)

*/
myApp := defineApp("samfisherirl", "Github.ahk")
; this example refers to my repo http://github.com/samfisherirl/github.ahk

path_of_app := A_MyDocuments "\github.ahk"
; set where my application is stored on the local computer

myApp.setPath(path_of_app)

myApp.connectGithubAPI()

update := myApp.checkforUpdate()

if (update) {
    msg := update["repo"] . " version number " . update["version"] . " needs an update. Release notes include:`n" . update["releaseNotes"]
    Msgbox(msg)

    myApp.update()
    ;gets file from repo, if zip/7zip, extract
    ;then overwrite existing app
    ;updates log
}
else {
    msgbox("You're up to date!")
}
full code does not include native.ahk and github.ahk, both needed. find the full code here: https://github.com/samfisherirl/Auto-Update.ahk-AHK-v2-easily-update-ahk-apps-remotely
or here:

Code: Select all

; this is auto_update.ahk

; Include the JSON library

;get all needed files here https://github.com/samfisherirl/Auto-Update.ahk-AHK-v2-easily-update-ahk-apps-remotely


; Define a class for building dictionaries of 3 strings
class defineApp {
    __New(username, repo) {
        ; Create a new dictionary with the given strings
        this.username := username,
        this.repo := repo,
        this.downloadUrl := "",
        this.version := "",
        this.releaseNotes := "",
        this.appPath := "",
        this.extension := "",
        this.downloadPath := A_MyDocuments "\temp"
        this.logpath := A_MyDocuments "\log_updater_ahk.json"
    }
    ; Define a method for adding a dictionary of 3 strings to the array

    setPath(appPath) {
        this.appPath := appPath
    }

    connectGithubAPI() {
        ; retieve from github library latest releaseUrl, notes, and version
        git := Github(this.username, this.repo)
        this.downloadUrl := git.releaseUrl()
        this.version := git.version()
        this.releaseNotes := git.details()
        this.extension := "." git.zipORexe()
    }

    checkforUpdate() {
        jdata := this.loadLog()
		if (jdata) {
            if (this.version != jdata["version"]) {
                return jdata
            }
        }
		else {
		return False
		}
    }
    LoadLog() {
        if FileExist(this.logpath) {
            json_raw := FileRead(this.logpath)
            jdata := JSON.parse(json_raw)
            ;MsgBox(jdata["version"])
            return jdata
        } else {
            this.writeJSON()
            return 1
        }

    }

    printDic() {
        for key, value in this.OwnProps() {
            msg .= key . ": " . value . "`n"
        }
        return msg
    }

    writeJSON() {
        dic := {}
        list_of_kv := []
        x := 0
        try {
            FileDelete(this.logpath)
        } catch {
        }
        for key, value in this.OwnProps() {
            if (key != "__Item") {
                dic.%key% := value
            }
            list_of_kv.Push(dic)
        }
        val := JSON.stringify(dic)
        FileAppend(val . "`n`n", this.logpath)
        val := ""
    }

    Update() {
        ;gets file from repo, if zip, extract
        ;then overwrite existing app
        ;updates log
        git := Github(this.username, this.repo)
        git.download(this.downloadpath)
        extension := this.extension
        source := this.downloadpath . extension
        if (InStr(extension, "zip")) or (InStr(extension, "7z")) or (InStr(extension, "rar")) {
            this.zip()
        }
        else {
            FileMove(source, this.appPath)
        }
        this.version := git.version()
        this.writeJSON()

    }

    zip() {
        zipperPath := A_MyDocuments . "\7za"
        ziplog := A_MyDocuments . "\templog.txt"
        temp := this.downloadpath . this.extension
        SplitPath(this.appPath, ,&app)
        zipobj := Github("samfisherirl", "7za")
        if not (FileExist(zipperPath ".exe")) {
            zipobj.download(zipperPath)
        }
        zipperPath := zipperPath . ".exe"
        this.filechecker(zipperPath)
        this.selfReferentialLog()
        ;msgbox(command)
        try {
            FileMove(ziplog, ziplog ".old")
        } catch {
        }
        command := A_ComSpec " `"" zipperPath "`" x `"" temp "`" -y -o`"" app "`" >`"" ziplog "`""
        ;msgbox(command)
        fileappend(command, A_ScriptDir "\temp.txt")
        Run(command)
        if this.filechecker(ziplog) {
            msgbox(FileRead(ziplog))
        }
        else {
            msgbox("ERROR in exporting zip/rar/7z from local path in Documents")
        }

    }

    filechecker(thefile) {
        loop (50) {
            if fileexist(thefile) {
                sleep(400)
                return True
            } else {
                sleep(200)
            }
        }
        return False

    }
    selfReferentialLog(){
        for key, val in this.OwnProps() {
        msg .= key . val . "`n`n"
        }
        FileAppend(msg, A_ScriptDir "\errlog.txt")
    }
    ; setDic() {
    ;     dictionary := {}
    ;     for key, value in this.OwnProps() {
    ;         dictionary[key] := value
    ;     }
    ;     return dictionary
    ; }
    ; Add the new dictionary to the array
    ; this.dictionaries.push(defineApp)
    /*
        ; Define a method for serializing the array of dictionaries as JSON
        SerializeToJson() {
    ; Serialize the array of dictionaries as JSON
    jdata := JSON.stringify(this.dictionaries)
    ; Return the serialized JSON string
    return jdata
        }
    ; retreive github library data including url to download and version data
    */
}
https://github.com/samfisherirl
? /Easy-Auto-GUI-for-AHK-v2 ? /Useful-AHK-v2-Libraries-and-Classes : /Pulovers-Macro-Creator-for-AHKv2 :

Return to “Scripts and Functions (v2)”