def main():
    option_parser = optparse.OptionParser()

    option_parser.add_option(
        '--mode',
        default='dev',
        help='switch indicating how to archive build (dev is only valid value)'
    )
    option_parser.add_option('--target',
                             default='Release',
                             help='build target to archive (Debug or Release)')
    option_parser.add_option(
        '--arch',
        default=archive_utils.BuildArch(),
        help='specify that target architecure of the build')
    option_parser.add_option('--src-dir',
                             default='src',
                             help='path to the top-level sources directory')
    option_parser.add_option('--build-dir', help='ignored')
    option_parser.add_option('--extra-archive-paths',
                             default='',
                             help='comma-separated lists of paths containing '
                             'files named FILES, SYMBOLS and TESTS. These '
                             'files contain lists of extra files to be '
                             'that will be archived. The paths are relative '
                             'to the directory given in --src-dir.')
    option_parser.add_option('--build-number',
                             type='int',
                             help='The build number of the builder running '
                             'this script. we use it as the name of build '
                             'archive directory')
    option_parser.add_option('--dry-run',
                             action='store_true',
                             help='Avoid making changes, for testing')
    option_parser.add_option('--ignore',
                             default=[],
                             action='append',
                             help='Files to ignore')
    option_parser.add_option('--archive_host',
                             default=archive_utils.Config.archive_host)
    option_parser.add_option('--build-name',
                             default=None,
                             help="Name to use for build directory instead of "
                             "the slave build name")
    option_parser.add_option('--staging-dir',
                             help='Directory to use for staging the archives. '
                             'Default behavior is to automatically detect '
                             'slave\'s build directory.')
    chromium_utils.AddPropertiesOptions(option_parser)
    options, args = option_parser.parse_args()
    if args:
        raise archive_utils.StagingError('Unknown arguments: %s' % args)

    if not options.ignore:
        # Independent of any other configuration, these exes and any symbol files
        # derived from them (i.e., any filename starting with these strings) will
        # not be archived or uploaded, typically because they're not built for the
        # current distributon.
        options.ignore = archive_utils.Config.exes_to_skip_entirely

    if options.mode == 'official':
        option_parser.error('Official mode is not supported here')
    elif options.mode == 'dev':
        options.dirs = {
            # Built files are stored here, in a subdir. named for the build version.
            'www_dir_base': archive_utils.Config.www_dir_base + 'snapshots',

            # Symbols are stored here, in a subdirectory named for the build version.
            'symbol_dir_base': archive_utils.Config.www_dir_base + 'snapshots',
        }
    else:
        option_parser.error('Invalid options mode %s' % options.mode)

    if options.build_number is not None:
        s = StagerByBuildNumber(options)
    else:
        s = StagerByChromiumRevision(options)
    return s.ArchiveBuild()
    def ArchiveBuild(self):
        """Zips build files and uploads them, their symbols, and a change log."""
        result = 0
        if self._build_revision is None:
            raise archive_utils.StagingError('No build revision was provided')
        print 'Staging in %s' % self._staging_dir

        fparser = archive_utils.FilesCfgParser(self._files_file,
                                               self.options.mode,
                                               self.options.arch)
        files_list = fparser.ParseLegacyList()
        self._archive_files = archive_utils.ExpandWildcards(
            self._build_dir, files_list)
        archives_list = fparser.ParseArchiveLists()
        # Check files and revision numbers.
        all_files_list = self._archive_files + [
            item['filename'] for sublist in archives_list.values()
            for item in sublist
        ]
        all_files_list.append(self._version_file)
        not_found = archive_utils.VerifyFiles(all_files_list, self._build_dir,
                                              self.options.ignore)
        not_found_optional = []
        for bad_fn in not_found[:]:
            if fparser.IsOptional(bad_fn):
                not_found_optional.append(bad_fn)
                not_found.remove(bad_fn)
                # Remove it from all file lists so we don't try to process it.
                if bad_fn in self._archive_files:
                    self._archive_files.remove(bad_fn)
                for archive_list in archives_list.values():
                    archive_list[:] = [
                        x for x in archive_list if bad_fn != x['filename']
                    ]
        # TODO(mmoss): Now that we can declare files optional in FILES.cfg, should
        # we only allow not_found_optional, and fail on any leftover not_found
        # files?

        print 'last change: %s' % self._build_revision
        previous_revision = self.GetLastBuildRevision()
        # TODO(agable): This conditional only works for svn because git can't easily
        # compare revisions.
        if (slave_utils.GitOrSubversion(self._src_dir) == 'svn'
                and self._build_revision <= previous_revision):
            # If there have been no changes, report it but don't raise an exception.
            # Someone might have pushed the "force build" button.
            print 'No changes since last build (r%s <= r%s)' % (
                self._build_revision, previous_revision)
            return 0

        print 'build name: %s' % self._build_name

        archive_name = 'chrome-%s.zip' % self.TargetPlatformName()
        archive_file = self.CreateArchiveFile(archive_name,
                                              self._archive_files)[1]

        # Handle any custom archives.
        # TODO(mmoss): Largely copied from stage_build.py. Maybe refactor more of
        # this into archive_utils.py.
        archive_files = [archive_file]
        for archive_name in archives_list:
            # The list might be empty if it was all 'not_found' optional files.
            if not archives_list[archive_name]:
                continue
            if fparser.IsDirectArchive(archives_list[archive_name]):
                fileobj = archives_list[archive_name][0]
                # Copy the file to the path specified in archive_name, which might be
                # different than the dirname or basename in 'filename' (allowed by
                # 'direct_archive').
                stage_subdir = os.path.dirname(archive_name)
                stage_fn = os.path.basename(archive_name)
                chromium_utils.MaybeMakeDirectory(
                    os.path.join(self._staging_dir, stage_subdir))
                print 'chromium_utils.CopyFileToDir(%s, %s, dest_fn=%s)' % (
                    os.path.join(self._build_dir, fileobj['filename']),
                    os.path.join(self._staging_dir, stage_subdir), stage_fn)
                if not self.options.dry_run:
                    chromium_utils.CopyFileToDir(
                        os.path.join(self._build_dir, fileobj['filename']),
                        os.path.join(self._staging_dir, stage_subdir),
                        dest_fn=stage_fn)
                archive_files.append(
                    os.path.join(self._staging_dir, archive_name))
            else:
                custom_archive = self.CreateArchiveFile(
                    archive_name,
                    [f['filename'] for f in archives_list[archive_name]])[1]
                print 'Adding %s to be archived.' % (custom_archive)
                archive_files.append(custom_archive)

        # Generate a revisions file which contains the Chromium/WebKit/V8's
        # revision information.
        self.GenerateRevisionFile()

        www_dir = os.path.join(self._www_dir_base, self._build_path_component)
        gs_bucket = self.options.factory_properties.get('gs_bucket', None)
        gs_acl = self.options.factory_properties.get('gs_acl', None)
        gs_base = None
        if gs_bucket:
            gs_base = '/'.join(
                [gs_bucket, self._build_name, self._build_path_component])
        self._UploadBuild(www_dir, self.revisions_path, archive_files, gs_base,
                          gs_acl)

        # Archive Linux packages (if any -- only created for Chrome builds).
        if chromium_utils.IsLinux():
            linux_packages = (glob.glob(
                os.path.join(self._build_dir,
                             '*-r%s_*.deb' % self._chromium_revision)))
            linux_packages.extend(
                glob.glob(
                    os.path.join(self._build_dir,
                                 '*-%s.*.rpm' % self._chromium_revision)))
            for package_file in linux_packages:
                print 'SshCopyFiles(%s, %s, %s)' % (
                    package_file, self.options.archive_host, www_dir)
            if not self.options.dry_run:
                print 'SshMakeDirectory(%s, %s)' % (self.options.archive_host,
                                                    www_dir)
                self.MySshMakeDirectory(self.options.archive_host, www_dir,
                                        gs_base)

                for package_file in linux_packages:
                    self.MyMakeWorldReadable(package_file, gs_base)
                    self.MySshCopyFiles(package_file,
                                        self.options.archive_host,
                                        www_dir,
                                        gs_base,
                                        gs_acl=gs_acl)
                    # Cleanup archived packages, otherwise they keep accumlating since
                    # they have different filenames with each build.
                    os.unlink(package_file)

        self.UploadTests(www_dir, gs_base, gs_acl)

        if not self.options.dry_run:
            # Save the current build revision locally so we can compute a changelog
            # next time
            self.SaveBuildRevisionToSpecifiedFile(self.last_change_file)

            # Record the latest revision in the developer archive directory.
            latest_file_path = os.path.join(self._www_dir_base, 'LATEST')
            if chromium_utils.IsWindows():
                print 'Saving revision to %s' % latest_file_path
                if gs_base:
                    self.CopyFileToGS(self.last_change_file,
                                      gs_base,
                                      '..',
                                      mimetype='text/plain',
                                      gs_acl=gs_acl)
                if not gs_base or self._dual_upload:
                    self.SaveBuildRevisionToSpecifiedFile(latest_file_path)
            elif chromium_utils.IsLinux() or chromium_utils.IsMac():
                # Files are created umask 077 by default, so make it world-readable
                # before pushing to web server.
                self.MyMakeWorldReadable(self.last_change_file, gs_base)
                print 'Saving revision to %s:%s' % (self.options.archive_host,
                                                    latest_file_path)
                self.MySshCopyFiles(self.last_change_file,
                                    self.options.archive_host,
                                    latest_file_path,
                                    gs_base,
                                    '..',
                                    mimetype='text/plain',
                                    gs_acl=gs_acl)
            else:
                raise NotImplementedError(
                    'Platform "%s" is not currently supported.' % sys.platform)

        if len(not_found_optional):
            sys.stderr.write('\n\nINFO: Optional File(s) not found: %s\n' %
                             ', '.join(not_found_optional))
        if len(not_found):
            sys.stderr.write('\n\nWARNING: File(s) not found: %s\n' %
                             ', '.join(not_found))
        return result