func main() { op := optionparser.NewOptionParser() op.On("--address IPADDRESS", "Address to be used for the server mode. Defaults to 127.0.0.1", options) op.On("--autoopen", "Open the PDF file (MacOS X and Linux only)", options) op.On("-c NAME", "--config", "Read the config file with the given NAME. Default: 'publisher.cfg'", &configfilename) op.On("--credits", "Show credits and exit", showCredits) op.On("--no-cutmarks", "Display cutmarks in the document", layoutoptions) op.On("--data NAME", "Name of the XML data file. Defaults to 'data.xml'. Use '-' for STDIN", options) op.On("--dummy", "Don't read a data file, use '<data />' as input", options) op.On("-x", "--extra-dir DIR", "Additional directory for file search", extradir) op.On("--extra-xml NAME", "Add this file to the layout file", extraXML) op.On("--filter FILTER", "Run XPROC filter before publishing starts", options) op.On("--grid", "Display background grid. Disable with --no-grid", options) op.On("--ignore-case", "Ignore case when accessing files (on a case-insensitive file system)", options) op.On("--no-local", "Add local directory to the search path. Default is true", &add_local_path) op.On("--layout NAME", "Name of the layout file. Defaults to 'layout.xml'", options) op.On("--jobname NAME", "The name of the resulting PDF file (without extension), default is 'publisher'", options) op.On("--mainlanguage NAME", "The document's main language in locale format, for example 'en' or 'en_US'.", &mainlanguage) op.On("--outputdir=DIR", "Copy PDF and protocol to this directory", options) op.On("--port PORT", "Port to be used for the server mode. Defaults to 5266", options) op.On("--profile", "Run publisher with profiling on (internal use)", options) op.On("--quiet", "Run publisher in silent mode", options) op.On("--runs NUM", "Number of publishing runs ", options) op.On("--startpage NUM", "The first page number", layoutoptions) op.On("--show-gridallocation", "Show the allocated grid cells", layoutoptions) op.On("--systemfonts", "Use system fonts (not Win XP)", &useSystemFonts) op.On("--tempdir=DIR", "Use this directory instead of the system temporary directory", options) op.On("--trace", "Show debug messages and some tracing PDF output", layoutoptions) op.On("--timeout SEC", "Exit after SEC seconds", options) op.On("-v", "--var VAR=VALUE", "Set a variable for the publishing run", setVariable) op.On("--varsfile NAME", "Set variables for the publishing run from key=value... file", options) op.On("--verbose", "Print a bit of debugging output", options) op.On("--version", "Show version information", versioninfo) op.On("--wd DIR", "Change working directory", options) op.On("--xml", "Output as (pseudo-)XML (for list-fonts)", options) op.Command("clean", "Remove publisher generated files") op.Command("compare", "Compare files for quality assurance") op.Command("doc", "Open documentation") op.Command("list-fonts", "List installed fonts (use together with --xml for copy/paste)") op.Command("run", "Start publishing (default)") op.Command("server", "Run as http-api server on localhost port 5266 (configure with --address and --port)") op.Command("watch", "Start watchdog / hotfolder") err := op.Parse() if err != nil { log.Fatal("Parse error: ", err) } var command string switch len(op.Extra) { case 0: // no command given, run is the default command command = "run" case 1: // great command = op.Extra[0] default: // more than one command given, what should I do? command = op.Extra[0] } cfg, err = configurator.ReadFiles(filepath.Join(homedir, ".publisher.cfg"), "/etc/speedata/publisher.cfg") if err != nil { log.Fatal(err) } // When the user requests another working directory, we should // change into the given wd first, before reading the local // options wdIsSet := false if wd := getOption("wd"); wd != "" { wdIsSet = true err := os.Chdir(wd) if err != nil { log.Fatal(err) } log.Printf("Working directory now: %s", wd) pwd = wd } cfg.ReadFile(filepath.Join(pwd, configfilename)) // ... but if the local config file has a wd=... option, we should honor this // and also honor the settings in that publisher.cfg file if !wdIsSet { if wd := getOption("wd"); wd != "" { err := os.Chdir(wd) if err != nil { log.Fatal(err) } log.Printf("Working directory now: %s", wd) pwd = wd cfg.ReadFile(filepath.Join(pwd, configfilename)) } } if add_local_path { extra_dir = append(extra_dir, pwd) } if useSystemFonts { // FontFolder() is system dependent and defined in extra files ff, err := FontFolder() if err != nil { log.Fatal(err) } defaults["fontpath"] = ff } os.Setenv("SP_MAINLANGUAGE", mainlanguage) os.Setenv("SP_FONT_PATH", getOption("fontpath")) os.Setenv("SP_PATH_REWRITE", getOption("pathrewrite")) os.Setenv("IMGCACHE", getOption("imagecache")) if ed := cfg.String("DEFAULT", "extra-dir"); ed != "" { abspath, err := filepath.Abs(ed) if err != nil { log.Fatal("Cannot find directory", ed) } extra_dir = append(extra_dir, abspath) } os.Setenv("SD_EXTRA_DIRS", strings.Join(extra_dir, string(filepath.ListSeparator))) if extraxmloption := getOption("extraxml"); extraxmloption != "" { for _, xmlfile := range strings.Split(extraxmloption, ",") { extraxml = append(extraxml, xmlfile) } } os.Setenv("SD_EXTRA_XML", strings.Join(extraxml, ",")) verbose := false if getOption("verbose") != "" { verbose = true os.Setenv("SP_VERBOSITY", "1") fmt.Println("SD_EXTRA_DIRS:", os.Getenv("SD_EXTRA_DIRS")) fmt.Println("SD_EXTRA_XML:", os.Getenv("SD_EXTRA_XML")) } if getOption("ignore-case") == "true" { os.Setenv("SP_IGNORECASE", "1") if verbose { fmt.Println("Ignore case for file system access") } } var exitstatus int if getOption("profile") != "" { fmt.Println("Profiling publisher run. Removing lprof_* now.") os.Setenv("SD_PROFILER", "true") files, err := filepath.Glob("lprof_*") if err != nil { log.Fatal(err) } for _, filename := range files { err = os.Remove(filename) if err != nil { log.Fatal(err) } } } if seconds := getOption("timeout"); seconds != "" { num, err := strconv.Atoi(seconds) if err != nil { log.Fatal(err) } log.Printf("Setting timeout to %d seconds", num) go timeoutCatcher(num) } // There is no need for the internal daemon when we do the other commands switch command { case "run", "server": daemon = comm.NewServer() } switch command { case "run": jobname := getOption("jobname") finishedfilename := fmt.Sprintf("%s.finished", jobname) os.Remove(finishedfilename) if filter := getOption("filter"); filter != "" { if filepath.Ext(filter) != ".xpl" { filter = filter + ".xpl" } log.Println("Run filter: ", filter) os.Setenv("CLASSPATH", libdir+"/calabash.jar:"+libdir+"/saxon9he.jar") cmdline := "java com.xmlcalabash.drivers.Main " + filter run(cmdline) } exitstatus = runPublisher() // profiler requested? if getOption("profile") != "" { fmt.Println("Run 'summary.lua' on resulting lprof_* file.") files, err := filepath.Glob("lprof_*") if err != nil { log.Fatal(err) } if len(files) != 1 { log.Println("Profiling not done, expecting exactly one file matching lprof_*.") } else { cmdline := fmt.Sprintf(`"%s" --luaonly "%s/lua/summary.lua" -v %s`, getExecutablePath(), srcdir, files[0]) run(cmdline) } } ioutil.WriteFile(finishedfilename, []byte("finished\n"), 0600) // open PDF if necessary if getOption("autoopen") == "true" { openFile(jobname + ".pdf") } case "compare": if len(op.Extra) > 1 { dir := op.Extra[1] fi, err := os.Stat(dir) if err != nil { log.Fatal(err) } if !fi.IsDir() { log.Fatalf("%q must be a directory", dir) } absDir, err := filepath.Abs(dir) if err != nil { log.Fatal(err) } sp.DoCompare(absDir) } else { log.Println("Please give one directory") } case "clean": jobname := getOption("jobname") files, err := filepath.Glob(jobname + "*") if err != nil { log.Fatal(err) } for _, v := range files { switch filepath.Ext(v) { case ".vars", ".log", ".protocol", ".dataxml", ".status", ".finished": log.Printf("Removing %s", v) err = os.Remove(v) if err != nil { log.Println(err) } } if v == jobname+"-aux.xml" { log.Printf("Removing %s", v) err = os.Remove(v) if err != nil { log.Println(err) } } } case "doc": openFile(path_to_documentation) os.Exit(0) case "list-fonts": var xml string if getOption("xml") == "true" { xml = "xml" } cmdline := fmt.Sprintf(`"%s" --luaonly "%s/lua/sdscripts.lua" "%s" list-fonts %s`, getExecutablePath(), srcdir, inifile, xml) run(cmdline) case "watch": watch_dir := getOptionSection("hotfolder", "hotfolder") events := getOptionSection("events", "hotfolder") var hotfolder_events []hotfolder.Event for _, v := range strings.Split(events, ";") { pattern_command := strings.Split(v, ":") if len(pattern_command) < 2 { log.Fatal("Something is wrong with the configuration file. hotfolder section correct?") } hotfolder_event := new(hotfolder.Event) hotfolder_event.Pattern = regexp.MustCompile(pattern_command[0]) hotfolder_event.Command = &pattern_command[1] hotfolder_events = append(hotfolder_events, *hotfolder_event) } if watch_dir != "" { hotfolder.Watch(watch_dir, hotfolder_events) } else { log.Fatal("Problem with watch dir in section [hotfolder].") } case "server": runServer(getOption("port"), getOption("address"), getOption("tempdir")) default: log.Fatal("unknown command:", command) } if daemon != nil { daemon.Close() } showDuration() os.Exit(exitstatus) }
func main() { cfg := config.NewConfig(basedir) var commandlinebasedir string op := optionparser.NewOptionParser() op.On("--basedir DIR", "Base dir", &commandlinebasedir) op.Command("build", "Build go binary") op.Command("dashdoc", "Generate speedata Publisher documentation (for dash)") op.Command("doc", "Generate speedata Publisher documentation") op.Command("dist", "Generate zip files and windows installers") op.Command("mkreadme", "Make readme for installation/distribution") op.Command("sourcedoc", "Generate the source documentation") op.Command("translate", "Translate layout") err := op.Parse() if err != nil { log.Fatal(err) } var command string if len(op.Extra) > 0 { command = op.Extra[0] } else { op.Help() os.Exit(-1) } if commandlinebasedir != "" { cfg.SetBasedir(commandlinebasedir) } switch command { case "build": err := buildsp.BuildGo(cfg, filepath.Join(basedir, "bin"), "", "", "local") if err != nil { os.Exit(-1) } case "doc": err = makedoc(cfg) if err != nil { log.Fatal(err) } case "dashdoc": err = dashdoc.DoThings(cfg) if err != nil { log.Fatal(err) } case "genschema": err = genluatranslations.DoThings(basedir) if err != nil { log.Fatal(err) } err = genschema.DoThings(basedir) if err != nil { log.Fatal(err) } case "dist": fmt.Println("Generate ZIP files and windows installer") os.RemoveAll(cfg.Builddir) makedoc(cfg) destdir := filepath.Join(cfg.Builddir, "speedata-publisher") var srcbindir string if srcbindir = os.Getenv("LUATEX_BIN"); srcbindir == "" || !fileutils.IsDir(srcbindir) { fmt.Println("Error: environment variable LUATEX_BIN not set or does not point to a directory") os.Exit(-1) } t := texttemplate.Must(texttemplate.ParseFiles(filepath.Join(cfg.Srcdir, "other", "nsitemplate.txt"))) for i := 1; i < len(op.Extra); i++ { os_arch := strings.Split(op.Extra[i], "/") platform := os_arch[0] arch := os_arch[1] fmt.Println(platform, arch) d := filepath.Join(srcbindir, platform, arch, "default") if !fileutils.IsDir(d) { fmt.Println("Does not exist:", d, "... skipping") } else { bindir, err := filepath.EvalSymlinks(d) if err != nil { log.Fatal(err) } err = dirstructure.MkBuilddir(cfg, bindir) if err != nil { log.Fatal(err) } err = buildsp.BuildGo(cfg, filepath.Join(cfg.Builddir, "speedata-publisher", "bin"), platform, arch, "directory") if err != nil { os.Exit(-1) } os.Chdir(cfg.Builddir) zipname := fmt.Sprintf("speedata-publisher-%s-%s-%s.zip", platform, arch, cfg.Publisherversion) os.Remove(zipname) exec.Command("zip", "-rq", zipname, "speedata-publisher").Run() if platform == "windows" { exename := fmt.Sprintf("speedata-publisher-%s-%s-%s-installer.exe", platform, arch, cfg.Publisherversion) os.Remove(exename) data := struct { Exename string Sourcedir string Arch string }{ Exename: exename, Sourcedir: destdir, Arch: arch, } f, err := os.Create("installer.nsi") if err != nil { log.Fatal(err) } t.Execute(f, data) out, err := exec.Command("makensis", "installer.nsi").Output() if err != nil { fmt.Println(string(out)) log.Fatal(err) } f.Close() } } } if false { } case "mkreadme": if len(op.Extra) < 3 { fmt.Println("Not enough arguments, use `mkreadme <os> <destdir>'.") fmt.Println("Where <os> is one of 'linux', 'darwin' or 'windows'.") os.Exit(-1) } t := template.Must(template.ParseFiles("doc/installation.txt")) data := struct { Os string }{ op.Extra[1], } w, err := os.OpenFile(filepath.Join(op.Extra[2], "installation.txt"), os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0644) if err != nil { fmt.Println(err) os.Exit(-1) } err = t.Execute(w, data) if err != nil { fmt.Println(err) os.Exit(-1) } case "sourcedoc": // 1 = srcpath, 2 = outpath, 3 = assets, 4 = images err := sourcedoc.GenSourcedoc(filepath.Join(cfg.Srcdir, "lua"), filepath.Join(cfg.Builddir, "sourcedoc"), filepath.Join(cfg.Basedir(), "doc", "sourcedoc", "assets"), filepath.Join(cfg.Basedir(), "doc", "sourcedoc", "img")) if err != nil { log.Fatal(err) } case "translate": if len(op.Extra) > 1 { if len(op.Extra) > 2 { err = translatelayout.Translate(basedir, op.Extra[1], op.Extra[2]) if err != nil { log.Fatal(err) } } else { err = translatelayout.Translate(basedir, op.Extra[1], "") if err != nil { log.Fatal(err) } } } else { fmt.Println("translate needs the input and output filename: sphelper translate infile.xml [outfile.xml]") os.Exit(-1) } default: op.Help() os.Exit(-1) } }