aboutsummaryrefslogtreecommitdiff
path: root/src/wrapper
diff options
context:
space:
mode:
authorkitsunyan2018-03-10 21:10:43 +0000
committerkitsunyan2018-03-10 21:10:43 +0000
commitfd397b356e9be1d3572ace965ead57120803a0ac (patch)
treed9e6fe9f903ab935fa6df2e6862a97515caf926c /src/wrapper
Initial commitv0.1
Diffstat (limited to 'src/wrapper')
-rw-r--r--src/wrapper/alpm.nim146
-rw-r--r--src/wrapper/curl.nim123
2 files changed, 269 insertions, 0 deletions
diff --git a/src/wrapper/alpm.nim b/src/wrapper/alpm.nim
new file mode 100644
index 0000000..00b5b86
--- /dev/null
+++ b/src/wrapper/alpm.nim
@@ -0,0 +1,146 @@
+import
+ strutils,
+ "../utils"
+
+type
+ AlpmHandle* = object
+ AlpmDatabase* = object
+ AlpmPackage* = object
+
+ AlpmList*[T] = object
+ data*: T
+ prev*: ptr AlpmList[T]
+ next*: ptr AlpmList[T]
+
+ AlpmDepMod* {.pure, size: sizeof(cint).} = enum
+ no = 1,
+ eq = 2,
+ ge = 3,
+ le = 4,
+ gt = 5,
+ lt = 6
+
+ AlpmReason* {.pure, size: sizeof(cint).} = enum
+ explicit = 0,
+ depend = 1
+
+ AlpmDependency* = object
+ name*: cstring
+ version*: cstring
+ desc*: cstring
+ nameHash: culong
+ depMod*: AlpmDepMod
+
+ AlpmGroup* = object
+ name*: cstring
+ packages*: ptr AlpmList[ptr AlpmPackage]
+
+{.passL: "-lalpm".}
+
+proc newAlpmHandle*(root: cstring, dbpath: cstring, err: var cint): ptr AlpmHandle
+ {.cdecl, importc: "alpm_initialize".}
+
+proc release*(handle: ptr AlpmHandle): cint
+ {.cdecl, importc: "alpm_release".}
+
+proc setArch*(handle: ptr AlpmHandle, arch: cstring): cint
+ {.cdecl, importc: "alpm_option_set_arch".}
+
+proc vercmp*(a: cstring, b: cstring): cint
+ {.cdecl, importc: "alpm_pkg_vercmp".}
+
+proc errno*(handle: ptr AlpmHandle): cint
+ {.cdecl, importc: "alpm_errno".}
+
+proc errorAlpm*(errno: cint): cstring
+ {.cdecl, importc: "alpm_strerror".}
+
+proc register*(handle: ptr AlpmHandle, treeName: cstring, level: cint): ptr AlpmDatabase
+ {.cdecl, importc: "alpm_register_syncdb".}
+
+proc local*(handle: ptr AlpmHandle): ptr AlpmDatabase
+ {.cdecl, importc: "alpm_get_localdb".}
+
+proc packages*(db: ptr AlpmDatabase): ptr AlpmList[ptr AlpmPackage]
+ {.cdecl, importc: "alpm_db_get_pkgcache".}
+
+proc groups*(db: ptr AlpmDatabase): ptr AlpmList[ptr AlpmGroup]
+ {.cdecl, importc: "alpm_db_get_groupcache".}
+
+proc name*(db: ptr AlpmDatabase): cstring
+ {.cdecl, importc: "alpm_db_get_name".}
+
+proc `[]`*(db: ptr AlpmDatabase, name: cstring): ptr AlpmPackage
+ {.cdecl, importc: "alpm_db_get_pkg".}
+
+proc base*(pkg: ptr AlpmPackage): cstring
+ {.cdecl, importc: "alpm_pkg_get_base".}
+
+proc name*(pkg: ptr AlpmPackage): cstring
+ {.cdecl, importc: "alpm_pkg_get_name".}
+
+proc version*(pkg: ptr AlpmPackage): cstring
+ {.cdecl, importc: "alpm_pkg_get_version".}
+
+proc arch*(pkg: ptr AlpmPackage): cstring
+ {.cdecl, importc: "alpm_pkg_get_arch".}
+
+proc groups*(pkg: ptr AlpmPackage): ptr AlpmList[cstring]
+ {.cdecl, importc: "alpm_pkg_get_groups".}
+
+proc reason*(pkg: ptr AlpmPackage): AlpmReason
+ {.cdecl, importc: "alpm_pkg_get_reason".}
+
+proc depends*(pkg: ptr AlpmPackage): ptr AlpmList[ptr AlpmDependency]
+ {.cdecl, importc: "alpm_pkg_get_depends".}
+
+proc optional*(pkg: ptr AlpmPackage): ptr AlpmList[ptr AlpmDependency]
+ {.cdecl, importc: "alpm_pkg_get_optdepends".}
+
+proc provides*(pkg: ptr AlpmPackage): ptr AlpmList[ptr AlpmDependency]
+ {.cdecl, importc: "alpm_pkg_get_provides".}
+
+proc cfree*(data: pointer)
+ {.cdecl, importc: "free", header: "<stdlib.h>".}
+
+proc freeList*[T](list: ptr AlpmList[T])
+ {.cdecl, importc: "alpm_list_free".}
+
+proc freeListInner*[T](list: ptr AlpmList[T], fn: proc (data: pointer): void {.cdecl.})
+ {.cdecl, importc: "alpm_list_free_inner".}
+
+proc freeListFull*[T](list: ptr AlpmList[T]) =
+ list.freeListInner(cfree)
+ list.freeList()
+
+template withAlpm*(root: string, db: string, dbs: seq[string], arch: string,
+ handle: untyped, alpmDbs: untyped, errors: untyped, body: untyped): untyped =
+ block:
+ var errno: cint = 0
+ let handle = newAlpmHandle(root, db, errno)
+
+ if handle == nil:
+ raise commandError(trp("failed to initialize alpm library\n(%s: %s)\n").strip
+ .replace("%s", "$#") % [$errno.errorAlpm, db])
+
+ var alpmDbs = newSeq[ptr AlpmDatabase]()
+ var errors = newSeq[string]()
+ for dbName in dbs:
+ let alpmDb = handle.register(dbName, 1 shl 30)
+ if alpmDb != nil:
+ alpmDbs &= alpmDb
+ else:
+ errors &= trp("could not register '%s' database (%s)\n").strip
+ .replace("%s", "$#") % [dbName, $handle.errno.errorAlpm]
+
+ try:
+ discard handle.setArch(arch)
+ body
+ finally:
+ discard handle.release()
+
+iterator items*[T](list: ptr AlpmList[T]): T =
+ var listi = list
+ while listi != nil:
+ yield listi.data
+ listi = listi.next
diff --git a/src/wrapper/curl.nim b/src/wrapper/curl.nim
new file mode 100644
index 0000000..5f3e814
--- /dev/null
+++ b/src/wrapper/curl.nim
@@ -0,0 +1,123 @@
+import
+ strutils,
+ "../utils"
+
+type
+ CurlHandle* = object
+
+ CurlInstance* = object
+ handle: ptr CurlHandle
+ data: seq[char]
+
+ CurlOption {.pure, size: sizeof(cint).} = enum
+ followLocation = 52,
+ noSignal = 99,
+ timeoutMs = 155,
+ connectTimeoutMs = 156,
+ writeData = 10001,
+ url = 10002,
+ writeFunction = 20011
+
+ CurlError* = object of Exception
+
+{.passL: "-lcurl".}
+
+proc initCurlGlobal*(flags: clong): cint
+ {.cdecl, importc: "curl_global_init".}
+
+proc cleanupCurlGlobal*: void
+ {.cdecl, importc: "curl_global_cleanup".}
+
+proc newCurlHandle*: ptr CurlHandle
+ {.cdecl, importc: "curl_easy_init".}
+
+proc cleanup*(handle: ptr CurlHandle)
+ {.cdecl, importc: "curl_easy_cleanup".}
+
+proc errorCurl*(error: cint): cstring
+ {.cdecl, importc: "curl_easy_strerror".}
+
+proc setOption*(handle: ptr CurlHandle, option: CurlOption): cint
+ {.cdecl, importc: "curl_easy_setopt", varargs.}
+
+proc perform*(handle: ptr CurlHandle): cint
+ {.cdecl, importc: "curl_easy_perform".}
+
+proc escape*(handle: ptr CurlHandle, input: cstring, length: cint): cstring
+ {.cdecl, importc: "curl_easy_escape".}
+
+proc freeCurl*(data: pointer)
+ {.cdecl, importc: "curl_free".}
+
+proc escape*(instance: ref CurlInstance, s: string): string =
+ let esc = instance.handle.escape(s, 0)
+ if esc != nil:
+ let nesc = $esc
+ freeCurl(esc)
+ nesc
+ else:
+ ""
+
+proc curlWriteMemory(mem: array[csize.high, char], size: csize, nmemb: csize,
+ userdata: ref CurlInstance): csize {.cdecl.} =
+ let total = size * nmemb
+ if total > 0:
+ userData.data &= mem[0 .. total - 1]
+ total
+
+var refCount = 0
+
+template withCurlGlobal*(body: untyped): untyped =
+ block:
+ if refCount == 0:
+ if initCurlGlobal(0) != 0:
+ raise commandError(tr"failed to initialize curl library")
+ refCount += 1
+ try:
+ body
+ finally:
+ refCount -= 1
+ if refCount == 0:
+ cleanupCurlGlobal()
+
+template withCurl*(instance: untyped, body: untyped): untyped =
+ block:
+ let handle = newCurlHandle()
+ if handle == nil:
+ raise commandError(tr"failed to initialize curl handle")
+
+ var instance: ref CurlInstance
+ new(instance)
+ instance.handle = handle
+ instance.data = newSeq[char]()
+
+ proc raiseError(code: cint) =
+ if code != 0:
+ let msg = code.errorCurl
+ if msg != nil:
+ raise newException(CurlError, tr"failed to perform request" & (": $#" % [$msg]))
+ else:
+ raise newException(CurlError, tr"failed to perform request")
+
+ proc performInternal(url: string): seq[char] =
+ raiseError(handle.setOption(CurlOption.followLocation, (clong) 1))
+ raiseError(handle.setOption(CurlOption.noSignal, (clong) 1))
+ raiseError(handle.setOption(CurlOption.timeoutMs, (clong) 15000))
+ raiseError(handle.setOption(CurlOption.connectTimeoutMs, (clong) 15000))
+ raiseError(handle.setOption(CurlOption.url, url))
+ raiseError(handle.setOption(CurlOption.writeFunction, cast[pointer](curlWriteMemory)))
+ raiseError(handle.setOption(CurlOption.writeData, instance))
+ raiseError(handle.perform())
+ instance.data
+
+ proc performString(url: string): string =
+ let data = performInternal(url)
+ var str = newStringOfCap(data.len)
+ for c in data:
+ str.add(c)
+ str
+
+ try:
+ body
+ finally:
+ handle.cleanup()