]> git.e2factory.org Git - e2factory.git/commitdiff
Remove e2-build-numbers command.
authorTobias Ulmer <tu@emlix.com>
Fri, 14 Dec 2012 11:58:45 +0000 (12:58 +0100)
committerTobias Ulmer <tu@emlix.com>
Tue, 26 Feb 2013 18:07:13 +0000 (19:07 +0100)
This tool has not been in use for years. So now is the time to remove
it.  For backwards compatibility, the symlink is still installed, and a
small replacement tool prints out an error message, should anyone try to
use it.

The server component can go away as well.

Signed-off-by: Tobias Ulmer <tu@emlix.com>
doc/man/Makefile
doc/man/e2-build-numbers.1 [deleted file]
generic/e2lib.lua
local/e2-build-numbers.lua
local/e2-build.lua
local/e2tool.lua
server/Makefile [deleted file]
server/web/retrieve-build-numbers.lua.in [deleted file]

index 2f469b18621d403b74ae509b714e74fe3de6c5c9..cac541661f0df89558d004be90d0545a5aeb223a 100644 (file)
@@ -42,8 +42,7 @@ e2-install-e2.1 \
 e2-ls-project.1 \
 e2-new-source.1 \
 e2-playground.1 \
-e2.conf.5 \
-e2-build-numbers.1
+e2.conf.5
 
 MANPAGES5 = e2rc.5 e2config.5
 MANPAGES7 = e2global.7 e2intro.7 e2workflow.7
diff --git a/doc/man/e2-build-numbers.1 b/doc/man/e2-build-numbers.1
deleted file mode 100644 (file)
index f53a24d..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-.\" Man page for e2-build-numbers
-.\"
-.\" (c)2007 emlix GmbH
-.\"
-.TH e2-build-numbers 1 "Jun 17, 2008" "0.1"
-
-.SH NAME
-e2-build-numbers \- updates build-numbers for one, multiple or all results
-
-.SH SYNOPSIS
-e2-build-numbers [OPTION | RESULT ...]
-
-.SH DESCRIPTION
-This tool allows creating and maintaining a monotonically increasing
-build-number for each result. The build-numbers, together with the
-build-id is stored in the local project-file "proj/build-numbers".
-The build-number can be manually increased or synchronized with
-a central server. Build-numbers always strictly increase with each
-change. After synchronization, an environment file with suitable
-variable definitions is generated in "proj/build-numbers.env". This
-file can be included in "proj/env" with the following command:
-
-.nf
-  env "proj/build-numbers.env"
-.fi
-
-This tool implicitly operates in "tag" mode, that is, it computes
-the results fingerprint with sources specified in the "tag" field
-of the source configuration, if the source refers to version-controlled
-files.
-
-.SH RETURN VALUE
-Normally, exit status is 0. On error, it is non-zero.
-
-.SH OPTIONS
-.TP
-.BR \-\-no\-sync
-Do not synchronize with the server, just update local build-number file.
-.TP
-.BR
-.BR \-\-prefix=PREFIX
-Add a user-defined prefix before the local build-numbers.
-.TP
-.BR \-\-force
-Force increasing the build number for the results given on the
-command line, or all, if no results have been specified.
-.TP
-.BR \-\-dry\-run
-Do not change any files.
-.TP
-.BR \-\-help
-Show usage information.
-
-.P
-For further global options, see \fBe2intro\fR(7).
-
-.SH BUGS
-Doubtless there are many.
-
-.SH "SEE ALSO"
-.BR e2intro (7),
-.BR e2-build (1).
-
-.SH AUTHORS
-Gordon Hecker, Oskar Schirmer and Felix Winkelmann
-
-.SH COPYRIGHT
-(c)2007 emlix GmbH
index 7f3de38f409067a5e5bcff2df7eb866272819791..fe424c45382946fa89ca60679e7a3ecf2d800a94 100644 (file)
@@ -93,7 +93,6 @@ e2lib.globals = {
     -- @name cmdline
     cmdline = {},
     git_skip_checkout = true,
-    buildnumber_server_url = nil,
     template_path = string.format("%s/templates", buildconfig.SYSCONFDIR),
     extension_config = ".e2/extensions",
     e2config = ".e2/e2config",
@@ -997,11 +996,6 @@ function e2lib.use_global_config()
             e2lib.globals.logrotate = config.log.logrotate
         end
     end
-    if config.site and config.site.buildnumber_server_url ~= nil then
-        e2lib.globals.buildnumber_server_url = config.site.buildnumber_server_url
-        e2lib.log(3, string.format("e2lib.globals.buildnumber_server_url=%s",
-        tostring(config.site.buildnumber_server_url)))
-    end
     assert_type(config.site, "config.site", "table")
     assert_type(config.site.e2_branch, "config.site.e2_branch", "string")
     assert_type(config.site.e2_tag, "config.site.e2_tag", "string")
index 66b74280b7a2af051356f4f536f89f294803907f..4c1610249feac2f3a9be819cf4de0a2d3bcdc97c 100644 (file)
@@ -1,9 +1,11 @@
+--- e2-build-numbers command.
+-- This command was removed in e2factory 2.3.13.
+-- @module local.e2-build-numbers
+
 --[[
    e2factory, the emlix embedded build system
 
-   Copyright (C) 2007-2009 Gordon Hecker <gh@emlix.com>, emlix GmbH
-   Copyright (C) 2007-2009 Oskar Schirmer <os@emlix.com>, emlix GmbH
-   Copyright (C) 2007-2008 Felix Winkelmann, emlix GmbH
+   Copyright (C) Tobias Ulmer <tu@emlix.com>, emlix GmbH
 
    For more information have a look at http://www.e2factory.org
 
@@ -27,8 +29,7 @@
 
 local e2lib = require("e2lib")
 local e2tool = require("e2tool")
-local e2option = require("e2option")
-local policy = require("policy")
+local err = require("err")
 
 e2lib.init()
 local info, re = e2tool.local_init(nil, "build-numbers")
@@ -36,71 +37,6 @@ if not info then
     e2lib.abort(re)
 end
 
-e2option.documentation = [[
-usage:
-e2-buildnumbers [--no-sync]
-]]
-
-policy.register_commandline_options()
-e2option.flag("no-sync", "do not synchronize with the server")
-
-local opts = e2option.parse(arg)
--- get build mode from the command line
-local build_mode = policy.handle_commandline_options(opts, true)
-if not build_mode then
-    e2lib.abort("no build mode given")
-end
-info, re = e2tool.collect_project_info(info)
-if not info then
-    e2lib.abort(re)
-end
-local rc, re = e2tool.check_project_info(info)
-if not rc then
-    e2lib.abort(re)
-end
-
--- apply the standard build mode to all results
-for _,res in pairs(info.results) do
-    res.build_mode = build_mode
-end
-
--- read build numbers,
--- merge to results,
--- flush buildids,
--- calculate buildids,
--- merge back,
--- request new build numbers,
--- write new build numbers
-
-local rc, re
-rc, re = e2tool.buildnumber_read(info)
-if not rc then
-    e2lib.abort(re)
-end
-rc, re = e2tool.buildnumber_mergetoresults(info)
-if not rc then
-    e2lib.abort(re)
-end
--- recalculate build ids ids
-e2tool.flush_buildids(info)
-e2tool.calc_buildids(info)
-rc, re = e2tool.buildnumber_mergefromresults(info)
-if not rc then
-    e2lib.abort(re)
-end
-if opts["no-sync"] then
-    rc, re = e2tool.buildnumber_request_local(info)
-else
-    rc, re = e2tool.buildnumber_request(info)
-end
-if not rc then
-    e2lib.abort(re)
-end
-rc, re = e2tool.buildnumber_write(info)
-if not rc then
-    e2lib.abort(re)
-end
-e2tool.buildnumber_display(info.build_numbers, 1)
-e2lib.finish()
+e2lib.abort(err.new("e2-build-numbers is deprecated and has been removed"))
 
 -- vim:sw=4:sts=4:et:
index 29c8c67b8daa5cf807d99bb98e00317b804829d6..d77f653453fab38f97384b3cbed9a2bfd80d905d 100644 (file)
@@ -55,7 +55,6 @@ e2option.flag("wc-mode", "build selected results in working-copy mode")
 e2option.flag("force-rebuild", "force rebuilding even if a result exists [broken]")
 e2option.flag("playground", "prepare environment but do not build")
 e2option.flag("keep", "do not remove chroot environment after build")
-e2option.flag("buildnumber", "use real build numbers")
 e2option.flag("buildid", "display buildids and exit")
 -- cache is not yet initialized when parsing command line options, so
 -- remember settings in order of appearance, and perform settings as soon
@@ -191,19 +190,6 @@ if opts.release and not e2tool.e2_has_fixed_tag(info) then
     e2lib.abort("Failure: e2 is on pseudo tag while building in release mode.")
 end
 
-if opts["buildnumber"] then
-    e2lib.logf(1, "setting up build numbers")
-    local rc, re
-    rc, re = e2tool.buildnumber_read(info)
-    if not rc then
-        e2lib.abort(re)
-    end
-    rc, re = e2tool.buildnumber_mergetoresults(info)
-    if not rc then
-        e2lib.abort(re)
-    end
-end
-
 -- calculate buildids for selected results
 for _,r in ipairs(sel_res) do
     local bid, re = e2tool.buildid(info, r)
index e34ad00674213b9f41c7f7de5b20c599116827e0..2667b21b93b94bf2269b1ba0705f7d70db493791 100644 (file)
@@ -80,7 +80,6 @@ local cache = require("cache")
 -- @field chroot_groups_sorted table: sorted list of chroot groups
 -- @field ghash table: temporary list keeps hashes for chroot groups
 --                     (generated by buildid_chrootgroup())
--- @field build_numbers table: build numbers keyed by result names
 -- @field project_location string: project location relative to the servers
 -- @field release_id string: release identifiert XXX where do we initialize it?
 -- @field env table: env table
@@ -1183,12 +1182,6 @@ function e2tool.collect_project_info(info, skip_load_config)
     -- if x86_64 mode is requested.
     info.chroot_call_prefix["x86_64"] = ""
 
-    -- build number state file
-    info.buildnumber_file = string.format("%s/.e2/build-numbers", info.root)
-
-    -- build number table
-    info.build_numbers  = {}
-
     info.hashcache_file = string.format("%s/.e2/hashcache", info.root)
     rc, re = hashcache_setup(info)
     if not rc then
@@ -2333,321 +2326,6 @@ local function check_workingcopies(info)
     return true, nil
 end
 
---- parse build numbers from a string and store to the build number table
--- @param info the info table
--- @param s string: the string to parse
--- @param build_numbers table: build number table (optional)
--- @return bool
--- @return nil, an error object on error
-local function string2bn(info, s, build_numbers)
-    e2lib.logf(4, "string2bn()")
-    if not build_numbers then
-        build_numbers = info.build_numbers
-    end
-    local rc
-    local re = err.new("error parsing build numbers:")
-    e2lib.log(3, "parsing build numbers")
-    local line = 0
-    for l in s:gmatch("[^\n]+") do
-        line = line + 1
-        local bn = {}
-        local r
-        r, bn.bid, bn.status, bn.num = l:match(
-        ("([-%w_]+)%s+(%x+)%s+(%S+)%s+(%d+)"))
-        if not r then
-            re:append("parse error in line %d", line)
-            return false, re
-        end
-        e2lib.logf(4, "%s %s %s %s", r, bn.bid, bn.status, bn.num)
-        local oldbn = build_numbers[r]
-        if oldbn and oldbn.num and oldbn.num ~= bn.num then
-            bn.oldnum = oldbn.num
-        end
-        build_numbers[r] = bn
-    end
-    return true, nil
-end
-
---- serialize the build number table suitable for storage or network
--- transport
--- @param info info table
--- @param build_numbers table: build number table (optional)
--- @return s string: serialized build numbers, or nil
--- @return nil, an error object on error
-local function bn2string(info, build_numbers)
-    e2lib.logf(4, "bn2string()")
-    if not build_numbers then
-        build_numbers = info.build_numbers
-    end
-    local s = ""
-    for r,bn in pairs(build_numbers) do
-        e2lib.logf(4, "%s %s %s %s", r, bn.bid, bn.status, bn.num)
-        local s1 = string.format("%s %s %s %s\n",
-        r, bn.bid, bn.status, bn.num)
-        s = s .. s1
-    end
-    return s, nil
-end
-
---- write the build number file
--- @param info the info table
--- @param file string: the build number file (optional)
--- @param build_numbers table: build number table (optional)
--- @return bool
--- @return an error object on error
-local function buildnumber_write(info, file, build_numbers)
-    e2lib.logf(4, "e2tool.buildnumber_write()")
-    local rc, msg
-    if not file then
-        file = info.buildnumber_file
-    end
-    if not build_numbers then
-        build_numbers = info.build_numbers
-    end
-    local e = err.new("error writing build number file:")
-    e2lib.logf(3, "writing build numbers to %s", file)
-    local s, re = bn2string(info)
-    if not s then
-        e:cat(re)
-        return false, e
-    end
-    rc, re = e2lib.write_file(file, s)
-    if not rc then
-        e:cat(re)
-        return false, e
-    end
-    return true, nil
-end
-
---- read the build number file into the buildnumber table
--- @param info the info table
--- @param file string: the build number file (optional)
--- @param build_numbers table: build number table (optional)
--- @return bool
--- @return an error object on error
-function e2tool.buildnumber_read(info, file, build_numbers)
-    e2lib.logf(4, "e2tool.buildnumber_read()")
-    local rc, re, msg
-    if not file then
-        file = info.buildnumber_file
-    end
-    if not build_numbers then
-        build_numbers = info.build_numbers
-    end
-    local e = err.new("error reading build number file:")
-    e2lib.logf(3, "reading build-numbers from %s", file)
-    local s, re = e2lib.read_file(file)
-    if not s and e2lib.isfile(file) then
-        e:cat(re)
-        return false, e
-    elseif not s then
-        e2lib.warnf("WOTHER", "build number file does not exist")
-        s = ""
-    end
-    local rc, re = string2bn(info, s, build_numbers)
-    if not rc then
-        e:cat(re)
-        return false, e
-    end
-    return true, nil
-end
-
---- merge build numbers from the build number table to the results
--- @param info table: the info table
--- @return bool
--- @return nil, an error object on failure
-function e2tool.buildnumber_mergetoresults(info)
-    e2lib.log(3, string.format("merging build numbers to results"))
-    local e = err.new("merging build numbers to results:")
-    for r, res in pairs(info.results) do
-        local bn = info.build_numbers[r]
-        if not bn then
-            e2lib.warnf("WOTHER",
-            "no build number entry for result: %s", r)
-        elseif res.pbuildid == bn.id then
-            e2lib.log(3, string.format(
-            "applying build number to result: %s [%s]",
-            r, bn.num))
-            res.buildno = bn.num
-        else
-            e:append("pseudo buildid mismatch in result %s", r)
-        end
-    end
-    if e:getcount() > 1 then
-        return false, e
-    end
-    return true, nil
-end
-
---- merge build numbers and pbid from the result to the build number table
--- @param info table: the info table
--- @return bool
--- @return nil, an error object on failure
-function e2tool.buildnumber_mergefromresults(info)
-    e2lib.log(3, string.format("merging build numbers from results"))
-    for r, res in pairs(info.results) do
-        local bn = info.build_numbers[r]
-        if not bn then
-            e2lib.warnf("WOTHER",
-            "creating new build number entry for result: %s", r)
-            -- create a new entry
-            bn = {}
-            bn.status = "ok"
-            bn.num = res.buildno
-            info.build_numbers[r] = bn
-        end
-        bn.bid = pbuildid(info, r)
-        e2lib.logf(4, "%s %s %s %s", r, tostring(bn.bid), bn.status, bn.num)
-    end
-    return true, nil
-end
-
---- display buildnumbers
--- @param build_numbers table: build number table
--- @param loglevel (optional, default 2)
--- @return nil
-local function buildnumber_display(build_numbers, loglevel)
-    if not loglevel then
-        loglevel = 2
-    end
-    e2lib.log(loglevel, "displaying build-number table:")
-    e2lib.logf(loglevel, "%-20s %-40s %2s %5s %-7s",
-    "result", "pbuildid", "st", "num", "old")
-    for r,bn in pairs(build_numbers) do
-        local changed = ""
-        if bn.oldnum then
-            changed = string.format("[%d]", bn.oldnum)
-        end
-        e2lib.logf(loglevel, "%-20s %40s %2s %5d %-7s",
-        r, bn.bid, bn.status, bn.num, changed)
-    end
-end
-
---- request new build numbers from the server
--- @param info
--- @return bool
--- @return an error object on failure
-function e2tool.buildnumber_request(info)
-    e2lib.log(3, "requesting build numbers from server")
-
-    if e2lib.globals.buildnumber_server_url == nil then
-        return false, err.new("no build number server configured")
-    end
-
-    local rc, re
-    local e = err.new("error requesting build numbers")
-    local tmpdir = e2lib.mktempdir()
-    local tmpreq = string.format("%s/build-number.req.tmp", tmpdir)
-    local tmpres = string.format("%s/build-number.res.tmp", tmpdir)
-    local curlflags = "--create-dirs --silent --show-error --fail"
-    local url = string.format(
-    "'%s?project=%s&user=%s&host=%s'",
-    e2lib.globals.buildnumber_server_url, info.name,
-    e2lib.globals.osenv["USER"], e2lib.globals.hostname)
-    local args = string.format(
-    "%s " ..
-    "--header 'Content-type: text/plain' " ..
-    "--data-binary '@%s' %s -o %s",
-    curlflags,
-    tmpreq, url, tmpres)
-    rc, re = buildnumber_write(info, tmpreq)
-    if not rc then
-        e:append(re)
-        return false, e
-    end
-    e2lib.log(3, "sending request")
-    rc, re = e2lib.curl(args)
-    if not rc then
-        e:append(re)
-        return false, e
-    end
-    rc, re = e2tool.buildnumber_read(info, tmpres)
-    if not rc then
-        e:append(re)
-        return false, e
-    end
-    e2lib.rmtempdir(tmpdir)
-    return true, nil
-end
-
---- perform the buildnumber update without synchronizing to the server
--- @param info
--- @return bool
--- @return an error object on failure
-local function buildnumber_request_local(info)
-    e2lib.log(3, "requesting build numbers locally")
-    local rc, re
-    local req  -- the request
-    local sta  -- the state
-    local res  -- the response
-    local e = err.new("error in local buildnumber request")
-    -- compose the request
-    req = info.build_numbers
-    -- compose the state
-    sta = {}
-    rc, re = e2tool.buildnumber_read(info, nil, sta)
-    if not rc then
-        return false, e:cat(re)
-    end
-    -- run the update function locally
-    res = {}
-    rc, re = buildnumber_update(sta, req, res)
-    if not rc then
-        return false, e:cat(re)
-    end
-    -- convert the result to a string
-    local s
-    s, re = bn2string(info, res)
-    if not s then
-        return false, e:cat(re)
-    end
-    -- convert the string back into the info structure
-    rc, re = string2bn(info, s)
-    if not rc then
-        return false, e:cat(re)
-    end
-    return true
-end
-
---- update buildnumbers - usable on server side, or in --no-sync mode on the
--- client side
--- @param state table: build number table state
--- @param request table: build number table request
--- @param response table: build number table response
--- @return build number table
-local function buildnumber_update(state, request, response)
-    e2lib.log(4, "buildnumber_update()")
-    e2lib.log(4, "state:")
-    buildnumber_display(state, 4)
-    e2lib.log(4, "request")
-    buildnumber_display(request, 4)
-    for r,bn in pairs(request) do
-        local req = bn
-        local sta = state[r]
-        e2lib.logf(4, "checking status for %s", r)
-        if not sta then
-            sta = {}
-            sta.bid = req.bid
-            sta.num = 1
-            sta.status = "ok"
-            state[r] = sta
-        elseif sta.bid ~= req.bid or sta.num ~= req.num then
-            e2lib.logf(4, "increasing buildnumber for %s", r)
-            -- update status
-            sta.num = math.max(sta.num, req.num) + 1
-            sta.bid = req.bid
-            sta.status = "ok"
-        end
-        -- create the response
-        local res = {}
-        res.bid = sta.bid
-        res.num = sta.num
-        res.status = sta.status
-        response[r] = res
-    end
-    return true, nil
-end
-
 --- select the result and apply build options
 -- @param info
 -- @param r string: the result name
diff --git a/server/Makefile b/server/Makefile
deleted file mode 100644 (file)
index 1b2f739..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-#
-#  e2factory, the emlix embedded build system
-#
-#  Copyright (C) 2007-2009 Gordon Hecker <gh@emlix.com>, emlix GmbH
-#  Copyright (C) 2007-2009 Oskar Schirmer <os@emlix.com>, emlix GmbH
-#  Copyright (C) 2007-2008 Felix Winkelmann, emlix GmbH
-#
-#  For more information have a look at http://www.e2factory.org
-#
-#  e2factory is a registered trademark by emlix GmbH.
-#
-#  This file is part of e2factory, the emlix embedded build system.
-#
-#  e2factory is free software: you can redistribute it and/or modify
-#  it under the terms of the GNU General Public License as published by
-#  the Free Software Foundation, either version 3 of the License, or
-#  (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program.  If not, see <http://www.gnu.org/licenses/>.
-#
-
-#### Makefile for build-number and log server
-
-
-TOPLEVEL = ..
-
-include $(TOPLEVEL)/make.vars
-
-SERVER_VERSION = 0.1
-CFLAGS = -g -DVERSION=\"$(SERVER_VERSION)\" -DSHAREDIR=\"$(SHAREDIR)\" \
-       -DLIBEXECDIR=\"$(LIBEXECDIR)\" -DLUA_VERSION=\"$(LUA_VERSION)\"
-
-.PHONY: all clean install
-
-all: web/store-run-log.lua web/retrieve-build-numbers.lua
-
-clean:
-       rm -f *~ *.o web/*.lua
-
-web/%.lua: web/%.lua.in
-       sed -e 's,@LOGDIR@,$(SERVER_LOGDIR),g' \
-         <$< >$@
-
-install: all
-       mkdir -p $(DESTDIR)$(SHAREDIR)/e2-server/web
-       install -m644 web/*.lua $(DESTDIR)$(SHAREDIR)/e2-server/web
diff --git a/server/web/retrieve-build-numbers.lua.in b/server/web/retrieve-build-numbers.lua.in
deleted file mode 100644 (file)
index c0096af..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
--- retrieve-build-numbers.lua - fetch current or new build-numbers -*- Lua -*-
---
--- method: POST
---
--- body: result-lines of the form "<resultname> <buildid*> <buildnumber>"
---
--- query string:
---
---   project=<projectname>
---
--- response: same format as request body, with updated or same contents
-
-
-local cl = os.getenv("CONTENT_LENGTH")
-
-local function fail(msg)
-  print("Status: 500 Internal Server Error\n\n" .. msg)
-  os.exit(1)
-end
-
-if not cl then fail("no content-length") end
-
-local function readbn(str)
-  local t = {}
-  for ln in string.gmatch(str, "[^\n]*\n") do
-    if not string.match(ln, "^%s*$") then
-      local res, bid, status, num =
-       string.match(ln, "([-%w_]+)%s+(%x+)%s+(%S+)%s+(%d+)")
-      if res then
-       t[ res ] = { id = bid, num = num, status = status }
-      else
-       fail("invalid request line: " .. ln)
-      end
-    end
-  end
-  return t
-end
-
-local function writebn(f, t)
-  for k, v in pairs(t) do
-    f:write(k, " ", v.id, " ok ", v.num, "\n")
-  end
-end
-
-local bytes = tonumber(cl)
-
-if bytes == 0 then
-  fail("zero content-length")
-end
-
-local req = io.read(bytes) or fail("empty request")
-local usernums = readbn(req)
-local query = {}
-
-for k, v in string.gmatch(os.getenv("QUERY_STRING"), "(%w+)=([-%w_]+)") do
-  query[ k ] = v
-end
-
-if not query.project then fail("no project given") end
-
-local logdir = "@LOGDIR@/" .. query.project
-local numfile = logdir .. "/build-numbers"
-
-os.execute("mkdir -p '" .. logdir .. "'")
-
-local currentnums
-local f, msg = io.open(numfile, "r")
-local changed = not f
-
-if not f then
-  currentnums = usernums
-else
-  local i = f:read("*a")
-  if not i then
-    fail("empty request")
-  end
-  f:close()
-  currentnums = readbn(i)
-end
-
-for k, v in pairs(usernums) do
-  local r = currentnums[ k ]
-  if r then
-    if r.id == v.id and v.status ~= "force" then
-      v.num = r.num
-    else
-      r.num = r.num + 1
-      r.id = v.id
-      changed = true
-      v.num = r.num
-    end
-  else
-    currentnums[ k ] = v
-  end
-end
-
-if changed then
-  f, msg = io.open(numfile, "w")
-  if not f then
-    fail("can not write `" .. numfile .. "': " .. msg)
-  end
-  writebn(f, currentnums)
-  f:close()
-end
-
-print("Content-type: text/plain\n")
-
-writebn(io.stdout, usernums)