InitSearchCommand.java

/*
 * Copyright © 2024-2025 The CTAN Team and individual authors
 *
 * This file is distributed under the 3-clause BSD license.
 * See file LICENSE for details.
 */

package org.ctan.site.command;

import java.io.File;
import java.io.IOException;
import java.util.Map;

import org.ctan.site.CtanConfiguration;
import org.ctan.site.CtanDatabaseBundles;
import org.ctan.site.services.search.base.IndexingService;
import org.ctan.site.services.search.base.IndexingSession;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;

import io.dropwizard.core.cli.Command;
import io.dropwizard.core.setup.Bootstrap;
import io.dropwizard.hibernate.HibernateBundle;
import lombok.NonNull;
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;

/**
 * The class <code>InitSearchCommand</code> contains the command line command to
 * create or initialise the search index.
 *
 * @author <a href="mailto:gene@ctan.org">Gerd Neugebauer</a>
 */
public class InitSearchCommand extends Command {

    /**
     * This is the constructor for <code>InitIndexCommand</code>.
     */
    public InitSearchCommand() {

        super("init-search", "Initialise the search index");
    }

    /**
     * {@inheritDoc}
     *
     * @see io.dropwizard.core.cli.Command#configure(net.sourceforge.argparse4j.inf.Subparser)
     */
    @Override
    public void configure(Subparser cli) {

        cli.addArgument("-c", "--config", "--configuration")
            .dest("config")
            .type(String.class)
            .required(true)
            .setDefault("ctan.yml")
            .help("The configuration file");
    }

    /**
     * The method <code>initSearch</code> provides means to perform the
     * initialisations.
     *
     * @param bootstrap the Bootstrap context
     *
     * @param dir the base directory containing the index files
     * @throws IOException in case of an I/O error
     */
    private void initSearch(Bootstrap<?> bootstrap, @NonNull File dir)
            throws IOException {

        HibernateBundle<CtanConfiguration> siteDb =
                CtanDatabaseBundles.SITE_DB_BUNDLE;
        siteDb.initialize(bootstrap);

        try (var indexer = new IndexingSession(dir)// TODO ;
        // TODO SessionFactory session = siteDb.getSessionFactory()
        ) {
            // var store = new AuthorStore(session, indexer);
            // System.out.println(store.count());

            // TODO add stores arguments
            new IndexingService(dir).initializeIndices();
        }
    }

    /**
     * Executes when the user runs this command.
     *
     * @param bootstrap the bootstrap bootstrap
     * @param namespace the parsed command line namespace
     * @throws Exception if something goes wrong
     * @see io.dropwizard.core.cli.Command#run(io.dropwizard.core.setup.Bootstrap,
     *     net.sourceforge.argparse4j.inf.Namespace)
     */
    @Override
    public void run(Bootstrap<?> bootstrap, Namespace namespace)
            throws Exception {

        var config = namespace.getString("config");
        var mapper = new ObjectMapper(new YAMLFactory());
        var resource = InitSearchCommand.class.getClassLoader()
            .getResourceAsStream(config);
        if (resource == null) {
            System.err.println("*** config not found: " + config);
            return;
        }
        Map<?, ?> cfg = mapper.readValue(resource, Map.class);
        var dir = (String) ((Map<?, ?>) cfg.get("index")).get("directory");
        if (dir == null) {
            System.err.println("*** missing index.directory");
            return;
        }

        initSearch(bootstrap, new File(dir));
    }

}