com.bahmanm.karun.PackageCollection.java Source code

Java tutorial

Introduction

Here is the source code for com.bahmanm.karun.PackageCollection.java

Source

/*
 * Karun, a package manager for ArchLinux based on 'pacman'.
 * Copyright (C) 2011  Bahman Movaqar
 *
 * This program 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 2
 * 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, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
 * USA.
 */
package com.bahmanm.karun;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.compress.archivers.ArchiveException;
import org.apache.commons.lang.StringUtils;

/**
 * PackageCollection
 *
 * @author Bahman Movaqar (Bahman AT BahmanM.com)
 */
public class PackageCollection {

    /** Repository */
    private final String repo;
    /** Directory of sync and local database */
    private final String dbPathSystem;
    /** Temp directory containing extracted sync database(s) */
    private final File dbPathTempSync;
    /** Package collection */
    private final HashMap<String, Package> collection = new HashMap<String, Package>();

    public HashMap<String, Package> getCollection() {
        return collection;
    }

    /**
     * Constructor
     * 
     * @param repo Repository name e.g. 'community' or '*all*'
     * @param dbPath Absolute path to directory of repository database files.
     */
    public PackageCollection(String repo, String dbPath)
            throws IOException, FileNotFoundException, ArchiveException, PacmanConfPathException {
        this.repo = repo;
        this.dbPathSystem = dbPath;
        dbPathTempSync = Utils.createTempDir();
        if (repo.equals("*all*")) {
            extractAllDbArchives();
            populateCollection();
        } else {
            extractDbArchive(repo);
            populateCollectionRepo(repo);
        }
    }

    /**
     * Builds package collection for all repositories.
     */
    private void populateCollection() throws FileNotFoundException, IOException, PacmanConfPathException {
        ArrayList<String> repos = PacmanConfHelper.get().getRepos();
        for (int i = 0; i < repos.size(); i++)
            addSyncPackages(repos.get(i));
        addLocalPackages(false);
    }

    /**
     * Builds package collection.
     * @param repo The repository
     */
    private void populateCollectionRepo(String repo) throws IOException, FileNotFoundException, ArchiveException {
        addSyncPackages(repo);
        addLocalPackages(true);
    }

    /**
     * Adds packages in a 'sync' db to package collection.
     * @param dbFilePath Absolute path to .db file 
     */
    private void addSyncPackages(final String repo) throws FileNotFoundException, IOException {
        traversPkgDir(new File(dbPathTempSync.getAbsolutePath() + "/" + repo), new PackageAction() {

            @Override
            public void action(Package pkg) {
                pkg.setRepo(repo);
                collection.put(pkg.getName(), pkg);
            }
        });
    }

    /**
     * Adds packages in local database to collection.
     * 
     * @param onlyMatches Search only for those packages already in collection
     */
    private void addLocalPackages(final boolean onlyMatches) throws FileNotFoundException, IOException {
        traversPkgDir(new File(dbPathSystem + "/local/"), new PackageAction() {

            @Override
            public void action(Package pkg) {
                if (collection.containsKey(pkg.getName())) {
                    Package p = collection.get(pkg.getName());
                    p.setLocalVersion(pkg.getRepoVersion());
                } else {
                    if (!onlyMatches) {
                        collection.put(pkg.getName(), pkg);
                    }
                }
            }
        });
    }

    /**
     * Extracts all .db archives in temp directory.
     * 
     * @throws IOException
     * @throws ArchiveException 
     */
    private void extractAllDbArchives() throws IOException, ArchiveException {
        File dbDir = new File(dbPathSystem + "/sync/");
        File[] dbFiles = dbDir.listFiles(new FilenameFilter() {

            @Override
            public boolean accept(File dir, String name) {
                return name.endsWith(".db");
            }
        });
        for (int i = 0; i < dbFiles.length; i++) {
            String fileName = dbFiles[i].getName();
            File dir = new File(
                    dbPathTempSync.getAbsolutePath() + "/" + fileName.substring(0, fileName.length() - 3));
            if (dir.exists())
                return;
            dir.mkdir();
            Utils.extractTarGz(dbFiles[i].getAbsolutePath(), dir);
        }
    }

    /**
     * Extracts a .db archive in temp directory.
     * 
     * @param repo Repository
     * @throws IOException
     * @throws ArchiveException 
     */
    private void extractDbArchive(String repo) throws IOException, ArchiveException {
        File dbFile = new File(dbPathSystem + "/sync/" + repo + ".db");
        File dir = new File(dbPathTempSync.getAbsolutePath() + "/" + repo);
        if (dir.exists())
            return;
        dir.mkdir();
        Utils.extractTarGz(dbFile.getAbsolutePath(), dir);
    }

    /**
     * Traverses a package directory and performs an action on each package found.
     * 
     * @param dir Package directory
     * @param packageAction Action to perform on packages
     */
    private void traversPkgDir(File dir, PackageAction packageAction) throws FileNotFoundException, IOException {
        String[] fileList = dir.list();
        for (int i = 0; i < fileList.length; i++) {
            File f = new File(dir.getAbsolutePath() + "/" + fileList[i]);
            if (f.isDirectory()) {
                Package p = readPackage(f);
                packageAction.action(p);
            }
        }
    }

    /**
     * Reads package information from a package directory.
     * 
     * @param pkgDir Package directory
     * @return Package
     */
    private Package readPackage(File pkgDir) throws FileNotFoundException, IOException {
        File f = new File(pkgDir.getAbsolutePath() + "/desc");
        FileInputStream fis = new FileInputStream(f);
        DataInputStream dis = new DataInputStream(fis);
        BufferedReader br = new BufferedReader(new InputStreamReader(dis));
        String line = null;
        Package pkg = new Package();
        try {
            boolean name = false;
            boolean desc = false;
            boolean version = false;
            while ((line = br.readLine()) != null) {
                line = StringUtils.normalizeSpace(line);
                if (line.equals("%NAME%")) {
                    name = name ? false : true;
                } else if (line.equals("%VERSION%")) {
                    version = version ? false : true;
                } else if (line.equals("%DESC%")) {
                    desc = desc ? false : true;
                } else if (name) {
                    pkg.setName(line);
                    name = false;
                } else if (version) {
                    pkg.setRepoVersion(line);
                    version = false;
                } else if (desc) {
                    pkg.setDescription(line);
                    desc = false;
                }
            }
        } catch (IOException ex) {
            Logger.getLogger(PackageCollection.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                br.close();
                dis.close();
                fis.close();
            } catch (IOException ioex) {
                throw new IOException("Error closing stream or reader: " + ioex.getMessage());
            }
        }
        return pkg;
    }

    /**
     * What to do with a package
     */
    protected interface PackageAction {

        /**
         * What to do with a package
         * 
         * @param pkg The package
         */
        public abstract void action(Package pkg);
    }

    /**
     * Minimal representation of a package
     */
    public class Package {

        private String name = "";
        private String repo = "";
        private String localVersion = "";
        private String repoVersion = "";
        private String description = "";

        public String getDescription() {
            return description;
        }

        public void setDescription(String description) {
            this.description = description;
        }

        public String getLocalVersion() {
            return localVersion;
        }

        public void setLocalVersion(String localVersion) {
            this.localVersion = localVersion;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getRepo() {
            return repo;
        }

        public void setRepo(String repo) {
            this.repo = repo;
        }

        public String getRepoVersion() {
            return repoVersion;
        }

        public void setRepoVersion(String repoVersion) {
            this.repoVersion = repoVersion;
        }
    } // Package
}