Exemple #1
0
        static void XapFiles(ZipArchive zip, string dir) {
            ICollection<LanguageInfo> langs = FindSourceLanguages(dir);
            
            string manifestPath = Path.Combine(dir, "AppManifest.xaml");
            IList<Uri> assemblies;

            if (File.Exists(manifestPath)) {
                assemblies = GetManifestAssemblies(manifestPath);
            } else {
                assemblies = GetLanguageAssemblies(langs);
                // generate the manfiest
                using (Stream appManifest = zip.Create("AppManifest.xaml")) {
                    Chiron.ManifestTemplate.Generate(assemblies).Save(appManifest);
                }
            }

            AddAssemblies(zip, dir, assemblies);

            GenerateLanguagesConfig(zip, langs);

            AddPathDirectories(zip);

            // add files on disk last so they always overwrite generated files
            zip.CopyFromDirectory(dir, "");
            
            zip.Close();
        }
Exemple #2
0
        static void XapFiles(ZipArchive zip, string dir) {
            ICollection<LanguageInfo> langs;
            IList<Uri> assemblies, externals;

            string manifestPath = Path.Combine(dir, "AppManifest.xaml");
            if (File.Exists(manifestPath)) {
                langs = FindSourceLanguages(dir);
                assemblies = GetManifestAssemblies(manifestPath);

                // Note: because the manifest file already exists, nothing 
                // needs to be done to support TPEs: Chiron doesn't need to host
                // them because they are assumed to be a well-known internet location.
                externals = null;
            } else {
                using (Stream appManifest = zip.Create("AppManifest.xaml")) {
                    GenerateManifest(dir, out langs, out assemblies, out externals).Save(appManifest);
                }
            }

            AddAssemblies(zip, dir, assemblies);

            GenerateLanguagesConfig(zip, langs);

            AddPathDirectories(zip);

            // add files on disk last so they always overwrite generated files
            zip.CopyFromDirectory(dir, "");
            
            zip.Close();
        }
Exemple #3
0
        static void XapFiles(ZipArchive zip, string dir) {
            ICollection<LanguageInfo> langs;
            IList<Uri> assemblies, externals;

            string manifestPath = Path.Combine(dir, "AppManifest.xaml");
            if (File.Exists(manifestPath)) {
                langs = FindSourceLanguages(dir);
                GetManifestParts(manifestPath, out assemblies, out externals);
            } else {
                using (Stream appManifest = zip.Create("AppManifest.xaml")) {
                    GenerateManifest(dir, out langs, out assemblies, out externals).Save(appManifest);
                }
            }

            AddAssemblies(zip, dir, assemblies);

            GenerateLanguagesConfig(zip, langs);

            AddPathDirectories(zip);

            // add files on disk last so they always overwrite generated files
            zip.CopyFromDirectory(dir, "");
            
            zip.Close();
        }
Exemple #4
0
 // add directories that are on Chiron's path
 internal static void AddPathDirectories(ZipArchive zip) {
     if (Chiron.LocalPath != null) {
         foreach (var path in Chiron.LocalPath) {
             string[] splitPath = path.Split(Path.DirectorySeparatorChar);
             zip.CopyFromDirectory(path, splitPath[splitPath.Length - 1]);
         }
     }
 }
Exemple #5
0
 public override void ProcessRequest(HttpContext context) {
     InternalProcessRequest(context, delegate(string pdirpath, string path) {
         // create in memory XAP archive
         if (Directory.Exists(pdirpath)) {
             MemoryStream ms = new MemoryStream();
             ZipArchive xap = new ZipArchive(ms, FileAccess.Write);
             xap.CopyFromDirectory(pdirpath, "");
             xap.Close();
             var xapBuffer = ms.ToArray();
             context.Response.OutputStream.Write(xapBuffer, 0, xapBuffer.Length);
         } else {
             throw new HttpException(404, "Missing " + path);
         }
     });
 }
Exemple #6
0
        // Generates languages.config file
        // this is needed by the DLR to load arbitrary DLR-based languages implementations
        private static void GenerateLanguagesConfig(ZipArchive zip, ICollection<LanguageInfo> langs) {
            bool needLangConfig = false;
            foreach (LanguageInfo lang in langs) {
                if (lang.LanguageContext != "") {
                    needLangConfig = true;
                    break;
                }
            }

            // Only need language configuration file for non-builtin languages
            if (needLangConfig) {
                Stream outStream = zip.Create("languages.config");
                StreamWriter writer = new StreamWriter(outStream);
                writer.WriteLine("<Languages>");

                foreach (LanguageInfo lang in langs) {
                    writer.WriteLine("  <Language");
                    writer.WriteLine("            names=\"{0}\"", lang.GetNames());
                    writer.WriteLine("            languageContext=\"{0}\"", lang.LanguageContext);
                    writer.WriteLine("            extensions=\"{0}\"", lang.GetExtensionsString());
                    writer.WriteLine("            assemblies=\"{0}\"", lang.GetAssemblyNames());
                    writer.WriteLine("            external=\"{0}\"", lang.External);
                    writer.WriteLine("  />");
                    
                }

                writer.WriteLine("</Languages>");
                writer.Close();
            }
        }
Exemple #7
0
        // Adds assemblies with relative paths into the XAP file
        private static void AddAssemblies(ZipArchive zip, string dir, IList<Uri> assemblyLocations) {
            foreach (Uri uri in assemblyLocations) {
                if (IsPathRooted(uri)) {
                    continue;
                }

                string targetPath = uri.OriginalString;
                string localPath = Path.Combine(dir, targetPath);

                if (!File.Exists(localPath)) {
                    localPath = Chiron.TryGetAssemblyPath(targetPath);

                    if (localPath == null) {
                        throw new ApplicationException("Could not find assembly: " + uri);
                    }
                }

                zip.CopyFromFile(localPath, targetPath);

                // Copy PDBs if available
                string pdbPath = Path.ChangeExtension(localPath, ".pdb");
                string pdbTarget = Path.ChangeExtension(targetPath, ".pdb");
                if (File.Exists(pdbPath)) {
                    zip.CopyFromFile(pdbPath, pdbTarget);
                }
            }
        }
Exemple #8
0
        static int Main(string[] args)
        {
            ParseOptions(args);

            if (!_NoLogo) {
                Console.WriteLine(
                  "Chiron - Silverlight Dynamic Language Development Utility. Version {0}",
                  typeof(Chiron).Assembly.GetName().Version
                );
            }

            if (_Help) {
                Console.WriteLine(
            @"Usage: Chiron [<options>]

            Common usages:

              Chiron.exe /b
            Starts the web-server on port 2060, and opens the default browser
            to the root of the web-server. This is used for developing an
            application, as Chiron will rexap you application's directory for
            every request.

              Chiron.exe /d:app /z:app.xap
            Takes the contents of the app directory and generates an app.xap
            from it, which embeds the DLR and language assemblies according to
            the settings in Chiron.exe.config. This is used for deployment,
            so you can take the generated app.xap, along with any other files,
            and host them on any web-server.

            Options:

              Note: forward-slashes (/) in option names can be substituted for dashes (-).
            For example ""Chiron.exe -w"" instead of ""Chiron.exe /w"".

              /w[ebserver][:<port number>]
            Launches a development web server that automatically creates
            XAP files for dynamic language applications (runs /z for every
            request of a XAP file, but generates it in memory).
            Optionally specifies server port number (default: 2060)

              /b[rowser][:<start url>]
            Launches the default browser and starts the web server
            Implies /w, cannot be combined with /x or /z

              /z[ipdlr]:<file>
            Generates a XAP file, including dynamic language dependencies, and
            auto-generates AppManifest.xaml (equivalent of /m in memory),
            if it does not exist.
            Does not start the web server, cannot be combined with /w or /b

              /m[anifest]
            Saves the generated AppManifest.xaml file to disk
            Use /d to set the directory containing the sources
            Can only be combined with /d, /n and /s

              /d[ir[ectory]]:<path>
            Specifies directory on disk (default: the current directory).
            Implies /w.

              /r[efpath]:<path>
            Path where assemblies are located. Defaults to the same directory
            where Chiron.exe exists.
            Overrides appSettings.localAssemblyPath in Chiron.exe.config.

              /p[ath]:<path1;path2;..;pathn>
            Semi-colon-separated directories to be included in the XAP file,
            in addition to what is specified by /d

              /u[rlprefix]:<relative or absolute uri>
            Appends a relative or absolute Uri to each language assembly or extension
            added to the AppManifest.xaml. If a relative Uri is provided, Chiron
            will serve all files located in the /refpath at this Uri, relative to the
            root of the web-server.
            Overrides appSettings.urlPrefix in Chiron.exe.config.

              /nl /noLanguageDetection
            Without this flag, Chiron scans the current application directory for files
            with a valid language's file extension, and only makes those languages
            available to the XAP file. See /useExtensions for whether the languages
            assemblies or extension files are used.
            With this flag, no language-specific assemblies/extensions are added to the
            XAP, so the Silverlight application is responsible for parsing the
            languages.config file in the XAP and downloading the languages it needs.
            Overrides appSettings.detectLanguages in Chiron.exe.config.

              /e /useExtensions:true|false (default false)
            Toggles whether or not language and DLR assemblies are embedded in
            the XAP file, or whether their equivalent extension files are used.

              /a /anyAddress
            By default Chiron listens on just the loopback IP address, meaning it only
            works for local requests. Providing this flag will cause Chiron to
            listen on any IP address, making it an internet-facing webserver. This
            option should only be used during development when running the Silverlight
            app on one machine and testing on many machines; Chiron is not optimized as
            a production webserver.

              /x[ap[file]]:<file>
            Specifies XAP file to generate. Only XAPs a directory; does not
            generate a manifest or add dynamic language DLLs; see /z for that
            functionality.
            Does not start the web server, cannot be combined with /w or /b

              /notification
            Display notification icon

              /n[ologo]
            Suppresses display of the logo banner

              /s[ilent]
            Suppresses display of all output
            ");
            }
            else if (_Error != null) {
                return Error(1000, "options", _Error);
            }
            else if (!string.IsNullOrEmpty(_XapFile)) {
                try {
                    if (!_Silent)
                        Console.WriteLine("Generating XAP {0} from {1}", _XapFile, _Directory);

                    if (_XapDlr) {
                        XapBuilder.XapToDisk(_Directory, _XapFile);
                    } else {
                        ZipArchive xap = new ZipArchive(_XapFile, FileAccess.Write);
                        XapBuilder.AddPathDirectories(xap);
                        xap.CopyFromDirectory(_Directory, "");
                        xap.Close();
                    }
                }
                catch (Exception ex) {
                    return Error(1001, "xap", ex.Message);
                }
            }
            else if (_SaveManifest) {
                try {
                    string manifest = Path.Combine(_Directory, "AppManifest.xaml");
                    if (File.Exists(manifest)) {
                        return Error(3002, "manifest", "AppManifest.xaml already exists at path " + manifest);
                    }

                    // Generate the AppManifest.xaml file to disk, as we would if we were
                    // generating it in the XAP
                    XapBuilder.GenerateManifest(_Directory).Save(manifest);
                } catch (Exception ex) {
                    return Error(3001, "manifest", ex.Message);
                }
            }
            else {
                string uri = string.Format("http://localhost:{0}/", _Port);

                if (!_Silent)
                    Console.WriteLine("Chiron serving '{0}' as {1}", _Directory, uri);

                try {
                    HttpServer server = new HttpServer(_Port, _Directory);
                    server.Start();

                    if (_LaunchBrowser) {
                        if (_StartPage != null) {
                            uri += _StartPage;
                        }

                        ProcessStartInfo startInfo = new ProcessStartInfo(uri);
                        startInfo.UseShellExecute = true;
                        startInfo.WorkingDirectory = _Directory;

                        Process p = new Process();
                        p.StartInfo = startInfo;
                        p.Start();
                    }

                    if (_NotifyIcon) {
                        Thread notify = new Thread(
                            () => {
                                Application.EnableVisualStyles();
                                Application.SetCompatibleTextRenderingDefault(false);

                                var notification = new Notification(_Directory, _Port);
                                Application.Run();
                            }
                        );
                        notify.SetApartmentState(ApartmentState.STA);
                        notify.IsBackground = true;
                        notify.Start();
                    }

                    while (server.IsRunning) Thread.Sleep(500);
                } catch (Exception ex) {
                    return Error(2001, "server", ex.Message);
                }
            }

            return 0;
        }
Exemple #9
0
        bool TryProcessXapListingRequest(HttpSocket s, string uri, string path) {
            // path should end with '\' (for XAP listing)
            if (!path.EndsWith(Path.DirectorySeparatorChar.ToString())) return false;
            path = path.Substring(0, path.Length - 1);

            // must end with XAP
            if (string.Compare(Path.GetExtension(path), ".xap", StringComparison.OrdinalIgnoreCase) != 0)
                return false;

            // file must exist
            if (!File.Exists(path)) return false;

            // see if need to serve file from XAP
            string filename = null;
            int iq = uri.IndexOf('?');
            if (iq >= 0) filename = uri.Substring(iq + 1);

            ZipArchive xap = null;

            try {
                // open XAP file
                xap = new ZipArchive(path, FileAccess.Read);

                if (string.IsNullOrEmpty(filename)) {
                    // list contents
                    List<ZipArchiveFile> xapContents = new List<ZipArchiveFile>();
                    foreach (KeyValuePair<string, ZipArchiveFile> p in xap.entries) xapContents.Add(p.Value);
                    s.WriteTextResponse(200, "html", HtmlFormatter.FormatXapListing(uri, xapContents), false);
                    return true;
                }

                // server file from XAP
                ZipArchiveFile f = null;
                if (!xap.entries.TryGetValue(filename, out f)) {
                    s.WriteErrorResponse(404, "Resource not found in XAP");
                    return true;
                }

                // check mime type
                string mimeType = HttpSocket.GetMimeType(filename);
                if (string.IsNullOrEmpty(mimeType)) {
                    s.WriteErrorResponse(403);
                    return true;
                }

                // get the content
                byte[] body = new byte[(int)f.Length];
                if (body.Length > 0) {
                    using (Stream fs = f.OpenRead()) {
                        fs.Read(body, 0, body.Length);
                    }
                }

                // write the resposne
                s.WriteResponse(200, string.Format("Content-type: {0}\r\n", mimeType), body, false);
                return true;
            }
            catch {
                s.WriteErrorResponse(500, "error reading XAP");
                return true;
            }
            finally {
                if (xap != null) xap.Close();
            }
        }
Exemple #10
0
        static int Main(string[] args) {
            ParseOptions(args);

            if (!_nologo) {
                Console.WriteLine(
                  "Chiron - Silverlight Development Utility. Version {0}", 
                  typeof(Chiron).Assembly.GetName().Version
                );
            }

            if (_help) {
                Console.WriteLine(
@"Usage: Chiron [<options>]

Options:

  /w[ebserver][:<port number>]
    Launches a development web server that automatically creates
    XAP files for dynamic language applications (runs /z for every
    request of a XAP file, but generates it in memory).
    Optionally specifies server port number (default: 2060)

  /b[rowser][:<start url>]
    Launches the default browser and starts the web server
    Implies /w, cannot be combined with /x or /z

  /z[ipdlr]:<file>
    Generates a XAP file, including dynamic language DLLs, and
    auto-generates AppManifest.xaml (equivalent of /m in memory), 
    if it does not exist.
    Does not start the web server, cannot be combined with /w or /b

  /m[anifest]
    Saves the generated AppManifest.xaml file to disk
    Use /d to set the directory containing the sources
    Can only be combined with /d, /n and /s

  /d[ir[ectory]]:<path>
    Specifies directory on disk (default: the current directory)

  /r[efpath]:<path>
    Path where assemblies are located.
    Overrides appSettings.localAssemblyPath in Chiron.exe.config

  /p[ath]:<path1;path2;..;pathn>
    semi-color-separated directories to be included in the XAP file,
    in addition to what is specified by /d

  /l[ocalAppRoot]:<relative path>
    Path to look for script files on the web-server, rather than in
    the XAP file (which is default). Path is relative to the XAP file.
    If Chiron is generating the AppManifest.xaml, it will use this to 
    find which languages the application depends on.

  /e[xtUrlPrefix]:<absolute uri> (>= Silverlight 3 only)
    Does not put the assemblies inside the XAP file, and references the
    appropriate slvx files from the Uri provided.
    Overrides appSettings.externalUrlPrefix in Chiron.exe.config

  /u[rlprefix]:<relative or absolute uri>
    appends a relative or absolute Uri to each language assembly added
    to the AppManifest.xaml. Also does not put the assemblies inside the 
    xap. If it's a relative Uri and /w is also given, Chiron will serve
    the assemblies from the Uri, relative to the server root.
    Overrides appSettings.urlPrefix in Chiron.exe.config

  /x[ap[file]]:<file>
    Specifies XAP file to generate. Only XAPs a directory; does not
    generate a manifest or add dynamic language DLLs; see /z for that
    functionality.
    Does not start the web server, cannot be combined with /w or /b

  /n[ologo]
    Suppresses display of the logo banner

  /s[ilent]
    Suppresses display of all output
");
            }
            else if (_error != null) {
                return Error(1000, "options", _error);
            }
            else if (!string.IsNullOrEmpty(_xapfile)) {
                try {
                    if (!_silent)
                        Console.WriteLine("Generating XAP {0} from {1}", _xapfile, _dir);

                    if (_zipdlr) {
                        XapBuilder.XapToDisk(_dir, _xapfile);
                    } else {
                        ZipArchive xap = new ZipArchive(_xapfile, FileAccess.Write);
                        XapBuilder.AddPathDirectories(xap);
                        xap.CopyFromDirectory(_dir, "");
                        xap.Close();
                    }
                }
                catch (Exception ex) {
                    return Error(1001, "xap", ex.Message);
                }
            }
            else if (_saveManifest) {
                try {
                    string manifest = Path.Combine(_dir, "AppManifest.xaml");
                    if (File.Exists(manifest)) {
                        return Error(3002, "manifest", "AppManifest.xaml already exists at path " + manifest);
                    }

                    // Generate the AppManifest.xaml file to disk, as we would if we were
                    // generating it in the XAP
                    XapBuilder.GenerateManifest(_dir).Save(manifest);
                } catch (Exception ex) {
                    return Error(3001, "manifest", ex.Message);
                }
            }
            else {
                string uri = string.Format("http://localhost:{0}/", _port);

                if (!_silent)
                    Console.WriteLine("Chiron serving '{0}' as {1}", _dir, uri);

                try {
                    HttpServer server = new HttpServer(_port, _dir);
                    server.Start();

                    if (_browser) {
                        if (_startPage != null) {
                            uri += _startPage;
                        }

                        ProcessStartInfo startInfo = new ProcessStartInfo(uri);
                        startInfo.UseShellExecute = true;
                        startInfo.WorkingDirectory = _dir;

                        Process p = new Process();
                        p.StartInfo = startInfo;
                        p.Start();
                    }

                    while (server.IsRunning) Thread.Sleep(500);
                } catch (Exception ex) {
                    return Error(2001, "server", ex.Message);
                }
            }

            return 0;
        }
Exemple #11
0
        static int Main(string[] args)
        {
            ParseOptions(args);

            if (!_nologo) {
                Console.WriteLine(
            @"Microsoft(R) Silverlight(TM) Development Utility. Version {0}
            Copyright (c) Microsoft Corporation.  All rights reserved.
            ", typeof(Chiron).Assembly.GetName().Version);
            }

            if (_help) {
                Console.WriteLine(
            @"Usage: Chiron [<options>]

            General Options:

              /d[irectory]:<path>
            Specifies directory on disk (default: the current directory)

              /x[ap]:<file>
            Specifies XAP file to generate
            Does not start the web server, cannot be combined with /w or /b

              /n[ologo]
            Suppresses display of the logo banner

              /s[ilent]
            Suppresses display of all output

            Dynamic Language Options:

              /z[ipdlr]:<file>
            Like /x, but includes files needed for dynamic language apps
            Does not start the web server, cannot be combined with /w or /b

              /w[ebserver][:<port number>]
            Launches a development web server that automatically creates
            XAP files for dynamic language applications
            Optionally specifies server port number (default: 2060)

              /b[rowser][:<start url>]
            Launches the default browser and starts the web server
            Implies /w, cannot be combined with /x or /z

              /m[anifest]
            Saves the generated AppManifest.xaml file to disk
            Use /d to set the directory containing the sources
            Can only be combined with /d, /n and /s
            ");
            }
            else if (_error != null) {
                return Error(1000, "options", _error);
            }
            else if (!string.IsNullOrEmpty(_xapfile)) {
                try {
                    if (!_silent)
                        Console.WriteLine("Generating XAP {0} from {1}", _xapfile, _dir);

                    if (_zipdlr) {
                        XapBuilder.XapToDisk(_dir, _xapfile);
                    } else {
                        ZipArchive xap = new ZipArchive(_xapfile, FileAccess.Write);
                        xap.CopyFromDirectory(_dir, "");
                        xap.Close();
                    }
                }
                catch (Exception ex) {
                    return Error(1001, "xap", ex.Message);
                }
            }
            else if (_saveManifest) {
                try {
                    string manifest = Path.Combine(_dir, "AppManifest.xaml");
                    if (File.Exists(manifest)) {
                        return Error(3002, "manifest", "AppManifest.xaml already exists at path " + manifest);
                    }

                    // Generate the AppManifest.xaml file to disk, as we would if we were
                    // generating it in the XAP
                    XapBuilder.GenerateManifest(_dir).Save(manifest);
                } catch (Exception ex) {
                    return Error(3001, "manifest", ex.Message);
                }
            }
            else {
                string uri = string.Format("http://localhost:{0}/", _port);

                if (!_silent)
                    Console.WriteLine("Chiron serving '{0}' as {1}", _dir, uri);

                try {
                    HttpServer server = new HttpServer(_port, _dir);
                    server.Start();

                    if (_browser) {
                        if (_startPage != null) {
                            uri += _startPage;
                        }

                        ProcessStartInfo startInfo = new ProcessStartInfo(uri);
                        startInfo.UseShellExecute = true;
                        startInfo.WorkingDirectory = _dir;

                        Process p = new Process();
                        p.StartInfo = startInfo;
                        p.Start();
                    }

                    while (server.IsRunning) Thread.Sleep(500);
                } catch (Exception ex) {
                    return Error(2001, "server", ex.Message);
                }
            }

            return 0;
        }
Exemple #12
0
        static int Main(string[] args)
        {
            ParseOptions(args);

            if (!_nologo)
            {
                Console.WriteLine(
                    "Chiron - Silverlight Development Utility. Version {0}",
                    typeof(Chiron).Assembly.GetName().Version
                    );
            }

            if (_help)
            {
                Console.WriteLine(
                    @"Usage: Chiron [<options>]

Common usages:

  Chiron.exe /b
    Starts the web-server on port 2060, and opens the default browser
    to the root of the web-server. This is used for developing an
    application, as Chiron will rexap you application's directory for
    every request.
    
  Chiron.exe /d:app /z:app.xap
    Takes the contents of the app directory and generates an app.xap 
    from it, which embeds the DLR and language assemblies according to
    the settings in Chiron.exe.config. This is used for deployment,
    so you can take the generated app.xap, along with any other files,
    and host them on any web-server.

Options:

  Note: forward-slashes (/) in option names can be substituted for dashes (-).
        For example ""Chiron.exe -w"" instead of ""Chiron.exe /w"".

  /w[ebserver][:<port number>]
    Launches a development web server that automatically creates
    XAP files for dynamic language applications (runs /z for every
    request of a XAP file, but generates it in memory).
    Optionally specifies server port number (default: 2060)

  /b[rowser][:<start url>]
    Launches the default browser and starts the web server
    Implies /w, cannot be combined with /x or /z

  /z[ipdlr]:<file>
    Generates a XAP file, including dynamic language dependencies, and
    auto-generates AppManifest.xaml (equivalent of /m in memory), 
    if it does not exist.
    Does not start the web server, cannot be combined with /w or /b

  /m[anifest]
    Saves the generated AppManifest.xaml file to disk
    Use /d to set the directory containing the sources
    Can only be combined with /d, /n and /s

  /d[ir[ectory]]:<path>
    Specifies directory on disk (default: the current directory).
    Implies /w.

  /r[efpath]:<path>
    Path where assemblies are located. Defaults to the same directory
    where Chiron.exe exists.
    Overrides appSettings.localAssemblyPath in Chiron.exe.config.

  /p[ath]:<path1;path2;..;pathn>
    Semi-colon-separated directories to be included in the XAP file,
    in addition to what is specified by /d
    
  /u[rlprefix]:<relative or absolute uri>
    Appends a relative or absolute Uri to each language assembly or extension
    added to the AppManifest.xaml. If a relative Uri is provided, Chiron 
    will serve all files located in the /refpath at this Uri, relative to the
    root of the web-server.
    Overrides appSettings.urlPrefix in Chiron.exe.config.
  
  /l /detectLanguages:true|false (default true)
    Scans the current application directory for files with a valid language's
    file extension, and only makes those languages available to the XAP file.
    See /useExtensions for whether the languages assemblies or extension files
    are used.
    If false, no language-specific assemblies/extensions are added to the XAP,
    so the Silverlight application is responsible for parsing the languages.config
    file in the XAP and downloading the languages it needs.
    Overrides appSettings.detectLanguages in Chiron.exe.config.
  
  /e /useExtensions:true|false (default false)
    Toggles whether or not language and DLR assemblies are embedded in
    the XAP file, or whether their equivalent extension files are used.

  /x[ap[file]]:<file>
    Specifies XAP file to generate. Only XAPs a directory; does not
    generate a manifest or add dynamic language DLLs; see /z for that
    functionality.
    Does not start the web server, cannot be combined with /w or /b

  /notification
    Display notification icon
  
  /n[ologo]
    Suppresses display of the logo banner

  /s[ilent]
    Suppresses display of all output
");
            }
            else if (_error != null)
            {
                return(Error(1000, "options", _error));
            }
            else if (!string.IsNullOrEmpty(_xapfile))
            {
                try {
                    if (!_silent)
                    {
                        Console.WriteLine("Generating XAP {0} from {1}", _xapfile, _dir);
                    }

                    if (_zipdlr)
                    {
                        XapBuilder.XapToDisk(_dir, _xapfile);
                    }
                    else
                    {
                        ZipArchive xap = new ZipArchive(_xapfile, FileAccess.Write);
                        XapBuilder.AddPathDirectories(xap);
                        xap.CopyFromDirectory(_dir, "");
                        xap.Close();
                    }
                }
                catch (Exception ex) {
                    return(Error(1001, "xap", ex.Message));
                }
            }
            else if (_saveManifest)
            {
                try {
                    string manifest = Path.Combine(_dir, "AppManifest.xaml");
                    if (File.Exists(manifest))
                    {
                        return(Error(3002, "manifest", "AppManifest.xaml already exists at path " + manifest));
                    }

                    // Generate the AppManifest.xaml file to disk, as we would if we were
                    // generating it in the XAP
                    XapBuilder.GenerateManifest(_dir).Save(manifest);
                } catch (Exception ex) {
                    return(Error(3001, "manifest", ex.Message));
                }
            }
            else
            {
                string uri = string.Format("http://localhost:{0}/", _port);

                if (!_silent)
                {
                    Console.WriteLine("Chiron serving '{0}' as {1}", _dir, uri);
                }

                try {
                    HttpServer server = new HttpServer(_port, _dir);
                    server.Start();

                    if (_browser)
                    {
                        if (_startPage != null)
                        {
                            uri += _startPage;
                        }

                        ProcessStartInfo startInfo = new ProcessStartInfo(uri);
                        startInfo.UseShellExecute  = true;
                        startInfo.WorkingDirectory = _dir;

                        Process p = new Process();
                        p.StartInfo = startInfo;
                        p.Start();
                    }

                    if (_notifyIcon)
                    {
                        Thread notify = new Thread(
                            () => {
                            Application.EnableVisualStyles();
                            Application.SetCompatibleTextRenderingDefault(false);

                            var notification = new Notification(_dir, _port);
                            Application.Run();
                        }
                            );
                        notify.SetApartmentState(ApartmentState.STA);
                        notify.IsBackground = true;
                        notify.Start();
                    }

                    while (server.IsRunning)
                    {
                        Thread.Sleep(500);
                    }
                } catch (Exception ex) {
                    return(Error(2001, "server", ex.Message));
                }
            }

            return(0);
        }