summary refs log tree commit diff stats
path: root/compiler/nimblecmd.nim
blob: 9b647e67d7412b646575a952c57b7b6d450c8465 (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
#
#
#           The Nim Compiler
#        (c) Copyright 2012 Andreas Rumpf
#
#    See the file "copying.txt", included in this
#    distribution, for details about the copyright.
#

## Implements some helper procs for Nimble (Nim's package manager) support.

import parseutils, strutils, strtabs, os, options, msgs, lists

proc addPath*(path: string, info: TLineInfo) =
  if not contains(options.searchPaths, path):
    lists.prependStr(options.searchPaths, path)

proc versionSplitPos(s: string): int =
  result = s.len-2
  while result > 1 and s[result] in {'0'..'9', '.'}: dec result
  if s[result] != '-': result = s.len

const
  latest = "head"

proc `<.`(a, b: string): bool =
  # wether a has a smaller version than b:
  if a == latest: return false
  var i = 0
  var j = 0
  var verA = 0
  var verB = 0
  while true:
    let ii = parseInt(a, verA, i)
    let jj = parseInt(b, verB, j)
    # if A has no number left, but B has, B is preferred:  0.8 vs 0.8.3
    if ii <= 0 or jj <= 0: return jj > 0
    if verA < verB: return true
    elif verA > verB: return false
    # else: same version number; continue:
    inc i, ii
    inc j, jj
    if a[i] == '.': inc i
    if b[j] == '.': inc j

proc addPackage(packages: StringTableRef, p: string) =
  let x = versionSplitPos(p)
  let name = p.substr(0, x-1)
  if x < p.len:
    let version = p.substr(x+1)
    if packages[name] <. version:
      packages[name] = version
  else:
    packages[name] = latest

iterator chosen(packages: StringTableRef): string =
  for key, val in pairs(packages):
    let res = if val == latest: key else: key & '-' & val
    yield res

proc addNimblePath(p: string, info: TLineInfo) =
  if not contains(options.searchPaths, p):
    message(info, hintPath, p)
    lists.prependStr(options.lazyPaths, p)

proc addPathWithNimFiles(p: string, info: TLineInfo) =
  proc hasNimFile(dir: string): bool =
    for kind, path in walkDir(dir):
      if kind == pcFile and path.endsWith(".nim"):
        result = true
        break
  if hasNimFile(p):
    addNimblePath(p, info)
  else:
    for kind, p2 in walkDir(p):
      if hasNimFile(p2): addNimblePath(p2, info)

proc addPathRec(dir: string, info: TLineInfo) =
  var packages = newStringTable(modeStyleInsensitive)
  var pos = dir.len-1
  if dir[pos] in {DirSep, AltSep}: inc(pos)
  for k,p in os.walkDir(dir):
    if k == pcDir and p[pos] != '.':
      addPackage(packages, p)
  for p in packages.chosen:
    addNimblePath(p, info)

proc nimblePath*(path: string, info: TLineInfo) =
  addPathRec(path, info)
  addNimblePath(path, info)
[1]) printUsage() os.Exit(1) } switch os.Args[2] { case "apod", "nasa": apodCmd.Parse(os.Args[3:]) if apodCmd.Parsed() { execAPOD() } case "bpod", "bing": bpodCmd.Parse(os.Args[3:]) if bpodCmd.Parsed() { execBPOD() } default: fmt.Printf("Invalid service: %q\n", os.Args[2]) printUsage() os.Exit(1) } } func printUsage() { fmt.Println("Usage: cetus <command> <service> [<flags>]\n") fmt.Println("Commands: ") fmt.Println(" set Set the latest image as background") fmt.Println(" fetch Fetch the latest image information") fmt.Println(" version Print version") fmt.Println("\nServices: ") fmt.Println(" apod NASA Astronomy Picture of the Day") fmt.Println(" bpod Bing Photo of the Day") } // Check whether user has set CETUS_CACHE_DIR, if not then use the // XDG_CACHE_HOME. If XDG_CACHE_HOME is not set then $HOME/.config // should be used, according to XDG Base Directory Specification func getCacheDir() string { cacheDir := os.Getenv("CETUS_CACHE_DIR") if len(cacheDir) == 0 { cacheDir = os.Getenv("XDG_CACHE_HOME") } if len(cacheDir) == 0 { cacheDir = fmt.Sprintf("%s/%s/%s", os.Getenv("HOME"), ".cache", "cetus") } return cacheDir } func execAPOD() { // reqInfo holds all the parameters that needs to be // sent with the request. GetJson() will pack apiKey & // date in params map before sending it to another // function. Adding params here will not change the // behaviour of the function, changes have to be made // in GetJson() too. reqInfo := make(map[string]string) reqInfo["api"] = string(*apodAPI) reqInfo["apiKey"] = string(*apodKey) reqInfo["date"] = string(*apodDate) if *apodRand { reqInfo["date"] = apod.RandDate() } body, err := apod.GetJson(reqInfo) chkErr(err) if *apodDump { fmt.Printf(body) os.Exit(0) } res := apod.Res{} err = apod.UnmarshalJson(&res, body) chkErr(err) // res.Msg will be returned when there is error on // user input or the api server. if len(res.Msg) != 0 { fmt.Printf("Message: %s", res.Msg) os.Exit(1) } // If path-only is passed then it will only print the // path, even if quiet is passed. If the user wants // the program to be quiet then path-only shouldn't be // passed. If path-only is not passed & quiet is also // not passed then print the response. // // Path is only printed when the media type is an // image because res.HDURL is empty on non image media // type. if *apodPathOnly { fmt.Println(res.HDURL) } else if !*apodQuiet { apod.Print(res) } // Proceed only if the command was set because if it // was fetch then it's already finished & should exit // now. if os.Args[1] == "fetch" { os.Exit(0) } // Try to set background only if the media type is an image. // First it downloads the image to the cache directory and // then tries to set it with feh. If the download fails then // it exits with a non-zero exit code. if res.MediaType != "image" { os.Exit(0) } cacheDir := fmt.Sprintf("%s/%s", getCacheDir(), "apod") os.MkdirAll(cacheDir, os.ModePerm) file := fmt.Sprintf("%s/%s", cacheDir, reqInfo["date"]) // Check if the file is available locally, if it is // then don't download it again and set it from disk if _, err := os.Stat(file); os.IsNotExist(err) { err = background.Download(file, res.HDURL) chkErr(err) } else { chkErr(err) } err = background.Set(file) chkErr(err) } func execBPOD() { // reqInfo holds all the parameters that needs to be // sent with the request. GetJson() will pack apiKey & // date in params map before sending it to another // function. Adding params here will not change the // behaviour of the function, changes have to be made // in GetJson() too. reqInfo := make(map[string]string) reqInfo["api"] = string(*bpodAPI) if *bpodRand { reqInfo["random"] = "true" } body, err := bpod.GetJson(reqInfo) chkErr(err) if *bpodDump { fmt.Printf(body) os.Exit(0) } res, err := bpod.UnmarshalJson(body) chkErr(err) // Correct format res.Url = fmt.Sprintf("%s%s", "https://www.bing.com", res.Url) dt, err := time.Parse("20060102", res.StartDate) chkErr(err) res.StartDate = dt.Format("2006-01-02") // If path-only is passed then it will only print the // path, even if quiet is passed. If the user wants // the program to be quiet then path-only shouldn't be // passed. If path-only is not passed & quiet is also // not passed then print the response. // // Path is only printed when the media type is an // image because res.HDURL is empty on non image media // type. if *bpodPathOnly { fmt.Println(res.Url) } else if !*bpodQuiet { bpod.Print(res) } // Proceed only if the command was set because if it // was fetch then it's already finished & should exit // now. if os.Args[1] == "fetch" { os.Exit(0) } // Try to set background only if the media type is an image. // First it downloads the image to the cache directory and // then tries to set it with feh. If the download fails then // it exits with a non-zero exit code. cacheDir := fmt.Sprintf("%s/%s", getCacheDir(), "bpod") os.MkdirAll(cacheDir, os.ModePerm) file := fmt.Sprintf("%s/%s", cacheDir, res.StartDate) // Check if the file is available locally, if it is // then don't download it again and set it from disk if _, err := os.Stat(file); os.IsNotExist(err) { err = background.Download(file, res.Url) chkErr(err) } else { chkErr(err) } err = background.Set(file) chkErr(err) } func chkErr(err error) { if err != nil { fmt.Println(err) os.Exit(1) } }