summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2012-02-17 02:16:50 +0100
committerAraq <rumpf_a@web.de>2012-02-17 02:16:50 +0100
commit547e8aa418ee9a851a876e109b483fc987bd87df (patch)
treea2b7dfe509beef289b83b933c51abbb8829b8541
parent97366d44195a96075960749a0ea84ded582dce87 (diff)
parent6901a725d5718dc985243b93bd5bfc968f5b1521 (diff)
downloadNim-547e8aa418ee9a851a876e109b483fc987bd87df.tar.gz
Merge branch 'master' of github.com:Araq/Nimrod
-rwxr-xr-xcompiler/nimrod.ini6
-rwxr-xr-xlib/pure/times.nim13
-rw-r--r--tools/niminst/debcreation.nim227
-rwxr-xr-xtools/niminst/niminst.nim92
4 files changed, 336 insertions, 2 deletions
diff --git a/compiler/nimrod.ini b/compiler/nimrod.ini
index 4016328ae..b689ec1c4 100755
--- a/compiler/nimrod.ini
+++ b/compiler/nimrod.ini
@@ -122,3 +122,9 @@ flags = "/Q"
 [C_Compiler]
 path = r""
 flags = "-w"
+
+[deb]
+buildDepends: "gcc (>= 4:4.3.2)"
+pkgDepends: "gcc (>= 4:4.3.2)"
+shortDesc: "The Nimrod Compiler"
+licenses: "bin/nimrod,gpl2;lib/*,lgpl;"
diff --git a/lib/pure/times.nim b/lib/pure/times.nim
index 2347557dc..98b91a33d 100755
--- a/lib/pure/times.nim
+++ b/lib/pure/times.nim
@@ -377,4 +377,17 @@ proc getClockStr*(): string {.rtl, extern: "nt$1".} =
   result = intToStr(ti.hour, 2) & ':' & intToStr(ti.minute, 2) &
     ':' & intToStr(ti.second, 2)
 
+proc `$`*(day: TWeekDay): string =
+  ## stingify operator for ``TWeekDay``.
+  let lookup: array[TWeekDay, string] = ["Monday", "Tuesday", "Wednesday", "Thursday",
+      "Friday", "Saturday", "Sunday"]
+  return lookup[day]
+
+proc `$`*(m: TMonth): string =
+  ## stingify operator for ``TMonth``.
+  let lookup: array[TMonth, string] = ["January", "February", "March", "April",
+      "May", "June", "July", "August", "September", "October", "November",
+      "December"]
+  return lookup[m]
+
 {.pop.}
diff --git a/tools/niminst/debcreation.nim b/tools/niminst/debcreation.nim
new file mode 100644
index 000000000..287bd9a7b
--- /dev/null
+++ b/tools/niminst/debcreation.nim
@@ -0,0 +1,227 @@
+import osproc, times, os, strutils
+
+# http://www.debian.org/doc/manuals/maint-guide/
+
+# Required files for debhelper.
+# -- control
+# -- copyright
+# -- changelog
+# -- rules
+
+type
+  TDebOptions* = object
+    buildDepends*, pkgDepends*, shortDesc*: string
+    licenses*: seq[tuple[files, license: string]]
+
+template addN(r: string): expr =
+  result.add(r & "\n")
+
+proc createControl(pkgName, maintainer, shortDesc, desc: string,
+                   buildDepends, pkgDepends: string = ""): string =
+  ## pkgName: Should be the package name, no spaces.
+  ## maintainer: firstName lastName <email>
+  ## shortDesc: short description of the application
+  ## desc: long description of the application
+  ## buildDepends: what the build depends on (compiling from source),
+  ##               this needs to be in the format deb accepts. For example,
+  ##               for gcc: ``gcc (>= 4:4.3.2)``
+  ##               Multiple dependencies should be separated by commas.
+  ## pkgDepends: Same as buildDepends except that this specifies the
+  ##             dependencies that the compiled application depends on.
+  
+  
+  result = ""
+  
+  addN("Source: " & pkgName)
+  addN("Maintainer: " & maintainer)
+  addN("Section: misc")
+  addN("Priority: optional")
+  addN("Standards-Version: 3.9.2")
+  addN("Build-Depends: debhelper (>= 8)" & 
+        (if buildDepends != "": ", " & buildDepends else: ""))
+  addN("\n")
+  addN("Package: " & pkgName)
+  addN("Architecture: any")
+  addN("Depends: ${shlibs:Depends}, ${misc:Depends}" &
+        (if pkgDepends != "": ", " & pkgDepends else: ""))
+  
+  var formattedDesc = ""
+  for line in splitLines(desc):
+    if line == "":
+      formattedDesc.add(" .\n")
+    else:
+      formattedDesc.add(" " & line & "\n")
+  
+  addN("Description: " & shortDesc & "\n" & formattedDesc)
+
+proc createCopyright(pkgName, mtnName, mtnEmail, version: string, 
+                     licenses: seq[tuple[files, license: string]]): string =
+  ## pkgName: Package name
+  ## mtnName: Maintainer name
+  ## mtnEmail: Maintainer email
+  ## version: package version
+  ## licenses: files: This specifies the files that the `license` covers,
+  ##           for example, it might be ``lib/*`` to cover the whole ``lib`` dir
+  ##           license: This specifies the license, for example gpl2, or lgpl.
+  
+  result = ""
+  addN("Maintainer name: " & mtnName)
+  addN("Email-Address: " & mtnEmail)
+  addN("Date: " & $getTime())
+  addN("Package Name: " & pkgName)
+  addN("Version: " & version)
+  for f, license in items(licenses):
+    addN("Files: " & f)
+    addN("License: " & license)
+
+proc formatDateTime(t: TTimeInfo, timezone: string): string =
+  var day = ($t.weekday)[0..2] & ", "
+  
+  return "$1$2 $3 $4 $5:$6:$7 $8" % [day, intToStr(t.monthday, 2),
+    ($t.month)[0..2], $t.year, intToStr(t.hour, 2), intToStr(t.minute, 2),
+    intToStr(t.second, 2), timezone]
+
+proc createChangelog(pkgName, version, maintainer: string): string =
+  ## pkgName: package name
+  ## version: package version
+  ## maintainer: firstName lastName <email>
+  result = ""
+  addN(pkgName & " (" & version & "-1) unstable; urgency=low")
+  addN("")
+  addN("  * Initial release.")
+  addN("")
+  addN(" -- " & maintainer & "  " &
+       formatDateTime(getGmTime(getTime()), "+0000"))
+
+proc createRules(): string =
+  ## Creates a nimrod application-agnostic rules file for building deb packages.
+  ## Please note: this assumes the c sources have been built and the
+  ## ``build.sh`` and ``install.sh`` files are available.
+  result = ""
+  addN("#!/usr/bin/make -f")
+  addN("%:")
+  addN("\tdh $@\n")
+  addN("dh_install:")
+  addN("\tdh_install --sourcedir=debian/tmp")
+  addN("override_dh_auto_clean:")
+  addN("\tfind . -name *.o -exec rm {} \\;")
+  addN("override_dh_auto_build:")
+  addN("\t./build.sh")
+  addN("override_dh_auto_install:")
+  addN("\t./install.sh debian/tmp")
+
+proc createIncludeBinaries(binaries: seq[string]): string =
+  return join(binaries, "\n")
+
+proc createDotInstall(pkgName: string, binaries, config, docs,
+    lib: seq[string]): string =
+  result = ""
+  for b in binaries:
+    addN(pkgName / b & " " & "usr/bin/")
+  for c in config:
+    addN(pkgName / c & " " & "etc/")
+  for d in docs:
+    addN(pkgName / d & " " & "usr/share/doc/nimrod/")
+  for l1 in lib:
+    addN(pkgName / l1 & " " & "usr/lib/nimrod")
+
+proc makeMtn(name, email: string): string =
+  return name & " <" & email & ">"
+
+proc assertSuccess(exitCode: int) =
+  doAssert(exitCode == QuitSuccess)
+
+proc prepDeb*(packName, version, mtnName, mtnEmail, shortDesc, desc: string,
+  licenses: seq[tuple[files, license: string]], binaries,
+  config, docs, lib: seq[string],
+  buildDepends, pkgDepends = "") =
+  ## binaries/config/docs/lib: files relative to nimrod's root, that need to
+  ##   be installed.
+  
+  let pkgName = packName.toLower()
+  
+  var workingDir = getTempDir() / "niminst" / "deb"
+  var upstreamSource = (pkgName & "-" & version)
+  
+  echo("Making sure build.sh and install.sh are +x")
+  assertSuccess execCmd("chmod +x \"" & 
+    (workingDir / upstreamSource / "build.sh") & "\"")
+  assertSuccess execCmd("chmod +x \"" & 
+    (workingDir / upstreamSource / "install.sh") & "\"")
+  
+  var tarCmd = "tar pczf \"" & 
+      (pkgName & "_" & version & ".orig.tar.gz") &
+      "\" \"" & upstreamSource & "\"" 
+  echo(tarCmd)
+  assertSuccess execCmd("cd \"" & workingDir & "\" && " & tarCmd)
+  
+  echo("Creating necessary files in debian/")
+  createDir(workingDir / upstreamSource / "debian")
+  
+  template writeDebian(f, s: string): expr =
+    writeFile(workingDir / upstreamSource / "debian" / f, s)
+  
+  var controlFile = createControl(pkgName, makeMtn(mtnName, mtnEmail),
+      shortDesc, desc, buildDepends, pkgDepends)
+  echo("debian/control")
+  writeDebian("control", controlFile)
+  
+  var copyrightFile = createCopyright(pkgName, mtnName, mtnEmail, version,
+      licenses)
+  echo("debian/copyright")
+  writeDebian("copyright", copyrightFile)
+
+  var changelogFile = createChangelog(pkgName, version, 
+      makeMtn(mtnName, mtnEmail))
+  echo("debian/changelog")
+  writeDebian("changelog", changelogFile)
+
+  echo("debian/rules")
+  writeDebian("rules", createRules())
+
+  echo("debian/compat")
+  writeDebian("compat", "8")
+
+  echo("debian/" & pkgName & ".install")
+  writeDebian(pkgName & ".install",
+    createDotInstall(pkgName, binaries, config, docs, lib))
+
+  # Other things..
+  createDir(workingDir / upstreamSource / "debian" / "source")
+  echo("debian/source/format")
+  writeDebian("source" / "format",
+            "3.0 (quilt)")
+  echo("debian/source/include-binaries")
+  writeFile(workingDir / upstreamSource / "debian" / "source" / "include-binaries",
+            createIncludeBinaries(binaries))
+
+  echo("All done, you can now build.")
+  echo("Before you do however, make sure the files in " & 
+    workingDir / upstreamSource / "debian" & " are correct.")
+  echo("Change your directory to: " & workingDir / upstreamSource)
+  echo("And execute `debuild -us -uc` to build the .deb")
+
+when isMainModule:
+  #var controlFile = createControl("nimrod", "Dominik Picheta <morfeusz8@gmail.com>",
+  # "The Nimrod compiler", "Compiler for the Nimrod programming language", "gcc (>= 4:4.3.2)", "gcc (>= 4:4.3.2)")
+  
+  #echo(controlFile)
+  
+  #var copyrightFile = createCopyright("nimrod", "Dominik Picheta", "morfeusz8@a.b", "0.8.14",
+  #    @[("bin/nimrod", "gpl2"), ("lib/*", "lgpl")])
+      
+  #echo copyrightFile
+  
+  #var changelogFile = createChangelog("nimrod", "0.8.14", "Dom P <m@b.c>")
+  #echo(changelogFile)
+  
+  #echo(createRules())
+
+  prepDeb("nimrod", "0.8.14", "Dominik Picheta", "morfeusz8@gmail.com", 
+    "The Nimrod compiler", "Compiler for the Nimrod programming language",
+    @[("bin/nimrod", "gpl2"), ("lib/*", "lgpl")], 
+    @["bin/nimrod"], @["config/*"], @["doc/*"], @["lib/*"],
+    "gcc (>= 4:4.3.2)", "gcc (>= 4:4.3.2)")
+ 
+  
+  
\ No newline at end of file
diff --git a/tools/niminst/niminst.nim b/tools/niminst/niminst.nim
index 8f73ae93a..207df0d32 100755
--- a/tools/niminst/niminst.nim
+++ b/tools/niminst/niminst.nim
@@ -14,7 +14,7 @@ when haveZipLib:
   import zipfiles
 
 import
-  os, strutils, parseopt, parsecfg, strtabs, streams
+  os, strutils, parseopt, parsecfg, strtabs, streams, debcreation
 
 const
   maxOS = 20 # max number of OSes
@@ -30,7 +30,8 @@ type
     actionNone,   # action not yet known
     actionCSource # action: create C sources
     actionInno,   # action: create Inno Setup installer
-    actionZip     # action: create zip file
+    actionZip,    # action: create zip file
+    actionDeb     # action: prepare deb package
 
   TFileCategory = enum
     fcWinBin,     # binaries for Windows
@@ -56,6 +57,7 @@ type
     vars: PStringTable
     app: TAppType
     nimrodArgs: string
+    debOpts: TDebOptions
 
 const
   unixDirVars: array[fcConfig..fcLib, string] = [
@@ -86,6 +88,11 @@ proc initConfigData(c: var TConfigData) =
   c.uninstallScript = false
   c.vars = newStringTable(modeStyleInsensitive)
 
+  c.debOpts.buildDepends = ""
+  c.debOpts.pkgDepends = ""
+  c.debOpts.shortDesc = ""
+  c.debOpts.licenses = @[]
+
 proc firstBinPath(c: TConfigData): string =
   if c.binPaths.len > 0: result = c.binPaths[0]
   else: result = ""
@@ -121,6 +128,7 @@ Command:
   csource             build C source code for source based installations
   zip                 build the ZIP file
   inno                build the Inno Setup installer
+  deb                 create files for debhelper
 Options:
   -o, --output:dir    set the output directory
   --var:name=value    set the value of a variable
@@ -145,6 +153,7 @@ proc parseCmdLine(c: var TConfigData) =
           of "csource": incl(c.actions, actionCSource)
           of "zip": incl(c.actions, actionZip)
           of "inno": incl(c.actions, actionInno)
+          of "deb": incl(c.actions, actionDeb)
           else: quit(Usage)
       else:
         c.infile = addFileExt(key.string, "ini")
@@ -266,6 +275,36 @@ proc parseIniFile(c: var TConfigData) =
         of "innosetup": pathFlags(p, k.key, v, c.innoSetup)
         of "ccompiler": pathFlags(p, k.key, v, c.ccompiler)
         of "linker": pathFlags(p, k.key, v, c.linker)
+        of "deb":
+          case normalize(k.key)
+          of "builddepends":
+            c.debOpts.buildDepends = v
+          of "packagedepends", "pkgdepends":
+            c.debOpts.pkgDepends = v
+          of "shortdesc":
+            c.debOpts.shortDesc = v
+          of "licenses":
+            # file,license;file,license;
+            var i = 0
+            var file = ""
+            var license = ""
+            var afterComma = false
+            while i < v.len():
+              case v[i]
+              of ',':
+                afterComma = true
+              of ';':
+                if file == "" or license == "":
+                  quit(errorStr(p, "Invalid `licenses` key."))
+                c.debOpts.licenses.add((file, license))
+                afterComma = false
+                file = ""
+                license = ""
+              else:
+                if afterComma: license.add(v[i])
+                else: file.add(v[i])
+              inc(i)
+          else: quit(errorStr(p, "unknown variable: " & k.key))
         else: quit(errorStr(p, "invalid section: " & section))
 
       of cfgOption: quit(errorStr(p, "syntax error"))
@@ -415,6 +454,52 @@ when haveZipLib:
     else:
       quit("Cannot open for writing: " & n)
 
+# -- prepare build files for .deb creation
+
+proc debDist(c: var TConfigData) =
+  if not existsFile("build.sh"): quit("No build.sh found.")
+  if not existsFile("install.sh"): quit("No install.sh found.")
+  
+  if c.debOpts.shortDesc == "": quit("shortDesc must be set in the .ini file.")
+  if c.debOpts.licenses.len == 0:
+    echo("[Warning] No licenses specified for .deb creation.")
+  
+  # -- Copy files into /tmp/..
+  echo("Copying source to tmp/niminst/deb/")
+  var currentSource = getCurrentDir()
+  var workingDir = getTempDir() / "niminst" / "deb"
+  var upstreamSource = (c.name.toLower() & "-" & c.version)
+  
+  createDir(workingDir / upstreamSource)
+  
+  template copyNimDist(f, dest: string): stmt =
+    createDir((workingDir / upstreamSource / dest).splitFile.dir)
+    copyFile(currentSource / f, workingDir / upstreamSource / dest)
+  
+  # Don't copy all files, only the ones specified in the config:
+  copyNimDist(buildShFile, buildShFile)
+  copyNimDist(installShFile, installShFile)
+  createDir(workingDir / upstreamSource / "build")
+  for f in walkFiles(c.libpath / "lib/*.h"):
+    copyNimDist(f, "build" / extractFilename(f))
+  for osA in 1..c.oses.len:
+    for cpuA in 1..c.cpus.len:
+      var dir = buildDir(osA, cpuA)
+      for k, f in walkDir(dir):
+        if k == pcFile: copyNimDist(f, dir / extractFilename(f))
+  for cat in items({fcConfig..fcOther, fcUnix}):
+    for f in items(c.cat[cat]): copyNimDist(f, f)
+
+  # -- Create necessary build files for debhelper.
+
+  let mtnName = c.vars["mtnname"]
+  let mtnEmail = c.vars["mtnemail"]
+
+  prepDeb(c.name, c.version, mtnName, mtnEmail, c.debOpts.shortDesc,
+          c.description, c.debOpts.licenses, c.cat[fcUnixBin], c.cat[fcConfig],
+          c.cat[fcDoc], c.cat[fcLib], c.debOpts.buildDepends,
+          c.debOpts.pkgDepends)
+
 # ------------------- main ----------------------------------------------------
 
 var c: TConfigData
@@ -430,3 +515,6 @@ if actionZip in c.actions:
     zipdist(c)
   else:
     quit("libzip is not installed")
+if actionDeb in c.actions:
+  debDist(c)
+