File indexing completed on 2024-04-14 05:34:15

0001 /*
0002     SPDX-FileCopyrightText: 2011 Vishesh Yadav <vishesh3y@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #ifndef HGWRAPPER_H
0008 #define HGWRAPPER_H
0009 
0010 #include <QProcess>
0011 #include <QString>
0012 #include <QHash>
0013 #include <QTextCodec>
0014 #include <KFileItem>
0015 #include <Dolphin/KVersionControlPlugin>
0016 
0017 class QTextCodec;
0018 
0019 
0020 //TODO: Create signals for infoMessage and errorMessage which will be 
0021 //      caught by main plugin interface.
0022 
0023 /**
0024  * A singleton class providing implementation of many Mercurial commands
0025  */
0026 class HgWrapper : public QObject
0027 {
0028     Q_OBJECT
0029 public:
0030     explicit HgWrapper(QObject *parent = nullptr);
0031 
0032     static HgWrapper *instance();
0033     static void freeInstance();
0034 
0035     /**
0036      * Start a mercurial command with given arguments.
0037      *
0038      * @param hgCommand Command to be executed. eg. diff, status
0039      * @param arguments Arguments for the given command
0040      * @param primaryOperation Will emit primaryOperationFinished, 
0041      *               primaryOperationError signals.
0042      */
0043     void executeCommand(const QString &hgCommand,
0044                         const QStringList &arguments = QStringList(),
0045                         bool primaryOperation=false);
0046     /**
0047      * Start a mercurial command with given arguments and return until
0048      * process completes.
0049      *
0050      * @param hgCommand Command to be executed. eg. diff, status
0051      * @param arguments Arguments for the given command
0052      * @param primaryOperation Will emit primaryOperationCompleted, 
0053      *               primaryOperationError signals.
0054      * @return true if operations completed successfully, otherwise false
0055      */
0056     bool executeCommandTillFinished(const QString &hgCommand,
0057                         const QStringList &arguments = QStringList(),
0058                         bool primaryOperation=false);
0059     /**
0060      * Start a mercurial command with given arguments, write standard output
0061      * to output parameter and return till finished.
0062      *
0063      * @param hgCommand Command to be executed. eg. diff, status
0064      * @param arguments Arguments for the given command
0065      * @param output Append standard output of process to this string
0066      * @param primaryOperation Will emit primaryOperationCompleted, 
0067      *               primaryOperationError signals.
0068      * @return true if operations completed successfully, otherwise false
0069      */
0070     bool executeCommand(const QString &hgCommand,
0071                         const QStringList &arguments,
0072                         QString &output,
0073                         bool primaryOperation=false);
0074 
0075     /**
0076      * Get the root directory of Mercurial repository. Using 'hg root'
0077      *
0078      * @return String containing path of the root directory.
0079      */
0080     QString getBaseDir() const;
0081 
0082     /**
0083      * Sets the current directory being browsed with plugin enabled.
0084      * Updates base directory of repository accordingly
0085      */
0086     void setCurrentDir(const QString &directory);
0087 
0088     /**
0089      * Get the directory path that is currently used as the working directory
0090      * to execute the commands by the HgWrapper.
0091      */
0092     QString getCurrentDir() const;
0093 
0094     /**
0095      * Set the root directory of repository as working directory.
0096      */
0097     void setBaseAsWorkingDir();
0098 
0099     /**
0100      * Get FileName-ItemVersion pairs of the repository returned by 
0101      *
0102      * $hg status --modified --added --removed --deleted --unknown --ignored
0103      *
0104      * Hence returns files with ItemVersion
0105      *      - LocallyModifiedVersion
0106      *      - AddedVersion
0107      *      - RemovedVersion
0108      *      - RemovedVersion
0109      *      - UnversionedVersion
0110      *      - IgnoredVersion
0111      *      - MissingVersion
0112      *
0113      * @param result A hashmap containing FileName-ItemVersion pairs
0114      *
0115      */
0116     void getItemVersions(QHash<QString, KVersionControlPlugin::ItemVersion> &result);
0117 
0118     void addFiles(const KFileItemList &fileList);
0119     void removeFiles(const KFileItemList &fileList);
0120     bool renameFile(const QString &source, const QString &destination);
0121 
0122     /**
0123      * Commits changes made to the working directory.
0124      * @param message Commit message. Should not be empty.
0125      * @param files List of files to be committed. Files changed but not 
0126      *              listed here will be ignored during commit. 
0127      *              If the list is empty, all modified files will be 
0128      *              committed, the default behavior.
0129      * @param closeCurrentBranch Closes the current branch after commit.
0130      * @return true if successful, otherwise false
0131      */
0132     bool commit(const QString &message, 
0133                 const QStringList &files = QStringList(), 
0134                 bool closeCurrentBranch = false);
0135 
0136     /**
0137      * Create a new branch
0138      * @param name Name of new branch to be createdialog
0139      * @return true if successfully created, otherwise false
0140      */
0141     bool createBranch(const QString &name);
0142 
0143     /**
0144      * Update current working directory to another branch
0145      * @param name Name of the branch to which working directory
0146      *              has to be updated.
0147      * @return true if successful, otherwise false
0148      */
0149     bool switchBranch(const QString &name);
0150 
0151     /**
0152      * Create tag for current changeset(the changeset of working directory)
0153      * @param name Name of the new tag to be createdialog
0154      * @return true if successful, otherwise false
0155      */
0156     bool createTag(const QString &name);
0157 
0158     /**
0159      * Update working directory to a changeset named by given tag
0160      * @param name Tag of the changeset to which working directory
0161      *              has to be updated.
0162      * @return true if successful, otherwise false
0163      */
0164     bool switchTag(const QString &name);
0165 
0166     /**
0167      * Reverts all local changes made to working directory. Will update to 
0168      * last changeset of current branch, ie state just after last commit.
0169      */
0170     bool revertAll();
0171 
0172     /**
0173      * Reverts local changes made to selected files. All changes made to 
0174      * these files after last commit will be lost.
0175      */
0176     bool revert(const KFileItemList &fileList);
0177 
0178     /**
0179      * Undo's last transaction. Like commit, pull, push(to this repo).
0180      * Does not alter working directory.
0181      *
0182      * Use with care. Rollback cant be undone. See Mercurial man page FOR
0183      * more info.
0184      *
0185      * @param dryRun Do not actually perform action, but just print output 
0186      *              Used to check if Rollback can be done, and if yes then
0187      *              what will be rolled back.
0188      * @return true if successful, otherwise false
0189      */
0190     bool rollback(bool dryRun=false);
0191 
0192     /**
0193      * Checks if the working directory is clean, ie there are no 
0194      * uncommitted changes present.
0195      *
0196      * @return true if clean otherwise false
0197      */
0198     bool isWorkingDirectoryClean();
0199 
0200     QString getParentsOfHead();
0201     
0202     /**
0203      * Returns list of all branch names.
0204      */
0205     QStringList getBranches();
0206 
0207     /**
0208      * Returns list of all tags
0209      */
0210     QStringList getTags();
0211 
0212     inline QString readAllStandardOutput() {
0213         return QTextCodec::codecForLocale()->toUnicode(m_process.readAllStandardOutput());
0214     }
0215     
0216     inline QString readAllStandardError() {
0217         return QTextCodec::codecForLocale()->toUnicode(m_process.readAllStandardError());
0218     }
0219     
0220     /**
0221      * Check if some Mercurial operation is currently being executed or
0222      * about to be started.
0223      */
0224     inline bool isBusy() {
0225         return (m_process.state() == QProcess::Running ||
0226                 m_process.state() == QProcess::Starting);
0227     }
0228 
0229 public Q_SLOTS:
0230     /**
0231      * Try to terminate the currently running operation.
0232      */
0233     void terminateCurrentProcess();
0234 
0235 Q_SIGNALS:
0236     ///equivalent to the signals of QProcess
0237     void finished(int exitCode, QProcess::ExitStatus exitStatus);
0238     void errorOccurred(QProcess::ProcessError error);
0239     void started();
0240     void stateChanged(QProcess::ProcessState state);
0241     void primaryOperationFinished(int exitCode, QProcess::ExitStatus exitStatus);
0242     void primaryOperationError(QProcess::ProcessError error);
0243 
0244 private:
0245     ///Get and update m_hgBaseDir
0246     void updateBaseDir();
0247 
0248 private Q_SLOTS:
0249     void slotOperationCompleted(int exitCode, QProcess::ExitStatus exitStatus);
0250     void slotOperationError(QProcess::ProcessError error);
0251 
0252 private:
0253     static HgWrapper *m_instance;
0254 
0255     QProcess m_process;
0256     QTextCodec *m_localCodec;
0257 
0258     QString m_hgBaseDir;
0259     QString m_currentDir;
0260 
0261     bool m_primaryOperation; // to differentiate intermediate process
0262 };
0263 
0264 #endif // HGWRAPPER_H
0265