HomeForumSourceResearchGuide
Sign in to contribute to source.
Component .update by barry
expand copy to clipboardexpand
const int PARA_WIDTH = 60
const int PARA_INDENT = 4

data VersionData {
	int number
	char date[]
}

data UpdateStatus {
	char lastCheck[]
	char lastReminder[]
	bool disableReminders
	}

data ChangeLog {
	int version
	char date[]
	bool sourceBreak
	bool objectBreak
	char shortNote[]
	char releaseNotes[]
	String language[]
	String compiler[]
	String runtime[]
	String installation[]
	String stdlib[]
	String natlib[]
	}

component provides App requires io.Output out, data.IntUtil iu, data.StringUtil stringUtil, System sys, net.http.HTTPRequest req, data.json.JSONEncoder encoder, io.FileSystem fileSystem, io.File, time.Calendar cal {
	
	bool sourceBreak
	bool objectBreak
	
	void printParagraph(char txt[], int width, int indent)
		{
		String parts[] = stringUtil.explode(txt, " ")
		
		int currentWidth = 0
		
		for (int i = 0; i < parts.arrayLength; i++)
			{
			if (currentWidth + parts[i].string.arrayLength < width)
				{
				out.print(" $(parts[i].string)")
				currentWidth += parts[i].string.arrayLength
				}
				else
				{
				out.println("")
				for (int j = 0; j < indent; j++) out.print(" ")
				out.print(" $(parts[i].string)")
				currentWidth = parts[i].string.arrayLength
				}
			}
		
		out.println("")
		}
	
	void printList(char name[], String items[])
		{
		if (items.arrayLength > 0)
			{
			out.println(" $name ")
			for (int j = 0; j < items.arrayLength; j++)
				{
				out.print("  - ")
				printParagraph(items[j].string, PARA_WIDTH, PARA_INDENT)
				}
			}
		}
	
	void printChangeLog(ChangeLog changes[])
		{
		for (int i = changes.arrayLength-1; i != INT_MAX; i--)
			{
			out.println("\n-- Version $(changes[i].version) --")
			
			printList(" Language: ", changes[i].language)
			printList(" Compiler: ", changes[i].compiler)
			printList(" Runtime: ", changes[i].runtime)
			printList(" Installation: ", changes[i].installation)
			printList(" Standard library: ", changes[i].stdlib)
			printList(" Native libraries: ", changes[i].natlib)
			
			if (changes[i].sourceBreak) sourceBreak = true
			if (changes[i].objectBreak) objectBreak = true
			
			if (changes[i].shortNote.arrayLength != 0) printParagraph("\nQuick notes: $(changes[i].shortNote)", PARA_WIDTH, 0)
			if (changes[i].releaseNotes.arrayLength != 0) out.println("Detailed notes: $(changes[i].releaseNotes)")
			}
		}
	
	ChangeLog[] getChangeLog(int version)
		{
		ChangeLog result[] = encoder.jsonToArray(req.get("http://www.projectdana.com/dana/timeline/$version", null).content, typeof(ChangeLog[]), null)
		
		return result
		}
	
	void refreshUpdateTracker()
		{
		char home[] = sys.getDanaHome()
		
		UpdateStatus ustatus = new UpdateStatus()

		if (fileSystem.exists("$home/components/resources-ext/update/status.json"))
			{
			File fd = new File("$home/components/resources-ext/update/status.json", File.READ)
			ustatus = clone encoder.jsonToData(fd.read(fd.getSize()), typeof(UpdateStatus))
			fd.close()
			}

		DateTime today = cal.getTime()
		ustatus.lastCheck = "$(today.year)/$(today.month)/$(today.day)"
		ustatus.lastReminder = "$(today.year)/$(today.month)/$(today.day)"
		
		if (!fileSystem.exists("$home/components/resources-ext/update/"))
			fileSystem.createDirectory("$home/components/resources-ext/update/")
		
		File fd = new File("$home/components/resources-ext/update/status.json", File.CREATE)
		fd.write(encoder.jsonFromData(ustatus, null))
		fd.close()
		}

	int App:main(AppParam params[])
		{
		// -- check for a new version --
		
		HTTPResponse r = req.get("http://www.projectdana.com/dana/version", null)

		if (r == null)
			{
			out.println("[failed to connect to server]")
			return 1
			}

		if (r.responseCode != "200")
			{
			out.println("[failed to connect to server (HTTP error $(r.responseCode))]")
			return 1
			}
		
		VersionData vd = encoder.jsonToData(r.content, typeof(VersionData), null)

		if (vd == null)
			{
			out.println("[response format mismatch from server; please check manually for a new version at http://www.projectdana.com]")
			return 1
			}

		if (vd.number != sys.getVersion())
			{
			ChangeLog changes[] = getChangeLog(sys.getVersion())
			
			out.println("Updates since your current version:")
			
			if (changes.arrayLength == 0)
				out.println("(unknown - connection or server failure?)")
				else
				printChangeLog(changes)
			
			out.println("\nNew version available: $(vd.number)")
			out.println("Release date: $(vd.date)")
			if (sourceBreak && objectBreak) out.println("Note: this update breaks source code and compiled file compatibility (see above)")
			else if (sourceBreak) out.println("Note: this update breaks source code compatibility (see above)")
			else if (objectBreak) out.println("Note: this update breaks compiled object file compatibility (see above)")
			if (objectBreak) out.println("Note: you'll need to recompile any projects using 'dnc .' to work with this version")
			out.println("Visit http://www.projectdana.com to download for your platform")
			}
			else
			{
			out.println("[your version of Dana is up to date]")
			}
		
		// -- update status on when the most recent check was made --
		refreshUpdateTracker()

		return 0
		}

}
Revision history
To propose a new revision to this entity, use dana source put -uc your/new/version.dn -n .update -m "reason for update" -u yourUsername
Version 2 (this version) by barry
Notes for this version: Updates configuration file format to match compiler update.
Version 1 by barry