summary refs log tree commit diff stats
path: root/tools/downloader.nim
blob: dc7b636aa895e57689706053520ef7d228f80164 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# Helper that is run after Nim's installation.

import
  ui, asyncdispatch, httpclient, os, finish, registry, strutils

type
  Actions = object
    addToPath, startMenu, mingw, aporia: bool
  Controls = object
    apply: Button
    bar: ProgressBar
    lab: Label

const arch = $(sizeof(int)*8)

proc download(pkg: string; c: Controls) {.async.} =
  c.bar.value = 0
  var client = newAsyncHttpClient()
  proc onProgressChanged(total, progress, speed: BiggestInt) {.async.} =
    c.lab.text = "Downloading " & pkg & " " & $(speed div 1000) & "kb/s"
    c.bar.value = clamp(int(progress*100 div total), 0, 100)

  client.onProgressChanged = onProgressChanged
  # XXX give a destination filename instead
  let contents = await client.getContent("http://nim-lang.org/download/" & pkg & ".zip")
  let z = "dist" / pkg & ".zip"
  # XXX make this async somehow:
  writeFile(z, contents)
  c.bar.value = 100
  let olddir = getCurrentDir()
  try:
    setCurrentDir(olddir  / "dist")
    if os.execShellCmd("bin\\7zG.exe x " & pkg & ".zip") != 0:
      c.lab.text = "Unpacking failed: " & z
  finally:
    setCurrentdir(olddir)

  when false:
    var a: ZipArchive
    if open(a, z, fmRead):
      extractAll(a, "dist")
      close(a)
    else:
      c.lab.text = "Error: cannot open: " & z

proc apply(a: Actions; c: Controls) {.async.} =
  if a.mingw:
    await download("mingw" & arch, c)
  if a.aporia:
    await download("aporia-0.4.0", c)

  if a.addToPath:
    let desiredPath = expandFilename(getCurrentDir() / "bin")
    let p = getUnicodeValue(r"Environment", "Path",
      HKEY_CURRENT_USER)
    var alreadyInPath = false
    for x in p.split(';'):
      if x.len == 0: continue
      let y = try: expandFilename(if x[0] == '"' and x[^1] == '"':
                                    substr(x, 1, x.len-2) else: x)
              except: ""
      if y == desiredPath: alreadyInPath = true
    if not alreadyInPath:
      addToPathEnv(desiredPath)

  if a.startMenu:
    createStartMenuEntry()

  c.apply.text = "Quit"

proc main() =
  var mainwin = newWindow("Nim installer", 640, 280, true)
  mainwin.margined = true
  mainwin.onClosing = (proc (): bool = return true)

  let box = newVerticalBox(true)
  mainwin.setChild(box)

  var groupA = newGroup("Actions", true)
  box.add(groupA, false)
  var innerA = newVerticalBox(true)
  groupA.child = innerA

  let cbAddToPath = newCheckbox("Add Nim to PATH")
  innerA.add cbAddToPath
  let cbStartMenu = newCheckbox("Create start menu entry")
  innerA.add cbStartMenu

  var groupB = newGroup("Optional Components", true)
  box.add(groupB, false)
  var innerB = newVerticalBox(true)
  groupB.child = innerB

  let cbMingw = newCheckbox("Download Mingw")
  innerB.add cbMingw

  let cbAporia = newCheckbox("Download Aporia")
  innerB.add cbAporia

  var c = Controls(
    apply: newButton("Apply"),
    bar: newProgressBar(),
    lab: newLabel(""))

  innerB.add c.apply
  innerB.add c.bar
  innerB.add c.lab

  proc apply() =
    c.apply.text = "Abort"
    asyncCheck apply(Actions(addToPath: cbAddToPath.checked,
                  startMenu: cbStartMenu.checked,
                  mingw: cbMingw.checked,
                  aporia: cbAporia.checked), c)

    c.apply.onclick = proc () =
      ui.quit()
      system.quit()

  c.apply.onclick = apply

  show(mainwin)
  pollingMainLoop((proc (timeout: int) =
    if hasPendingOperations(): asyncdispatch.poll(timeout)), 10)

init()
main()