Initial commit

This commit is contained in:
Ade Attwood 2018-02-04 19:39:45 +00:00
commit 6fbc93e12e
13 changed files with 652 additions and 0 deletions

89
.gitignore vendored Normal file
View file

@ -0,0 +1,89 @@
# Created by https://www.gitignore.io/api/git,linux,macos,cmake,windows,visualstudiocode
### CMake ###
CMakeCache.txt
CMakeFiles
CMakeScripts
Testing
Makefile
cmake_install.cmake
install_manifest.txt
compile_commands.json
CTestTestfile.cmake
build
### Git ###
*.orig
### Linux ###
*~
# temporary files which can be created if a process still has a handle open of a deleted file
.fuse_hidden*
# KDE directory preferences
.directory
# Linux trash folder which might appear on any partition or disk
.Trash-*
# .nfs files are created when an open file is removed but is still being accessed
.nfs*
### macOS ###
*.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
### VisualStudioCode ###
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history
### Windows ###
# Windows thumbnail cache files
Thumbs.db
ehthumbs.db
ehthumbs_vista.db
# Folder config file
Desktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msm
*.msp
# Windows shortcuts
*.lnk
# End of https://www.gitignore.io/api/git,linux,macos,cmake,windows,visualstudiocode

8
.vscode/settings.json vendored Normal file
View file

@ -0,0 +1,8 @@
{
"files.associations": {
"iostream": "cpp"
},
"cSpell.words": [
"stoi"
]
}

57
.vscode/tasks.json vendored Normal file
View file

@ -0,0 +1,57 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "Build development",
"type": "shell",
"command": "./builder debug",
"problemMatcher": [
"$gcc"
],
"group": {
"kind": "build",
"isDefault": true
},
"presentation": {
"reveal": "always",
"focus": true
}
},
{
"label": "Build porduction",
"type": "shell",
"command": "./builder release",
"problemMatcher": [
"$gcc"
],
"presentation": {
"reveal": "always",
"focus": true
}
},
{
"label": "Package",
"type": "shell",
"command": "./builder package",
"problemMatcher": [
"$gcc"
],
"presentation": {
"reveal": "always",
"focus": true
}
},
{
"label": "Clean",
"type": "shell",
"command": "./builder clean",
"presentation": {
"reveal": "always",
"focus": true
},
"problemMatcher": [],
}
]
}

37
CMakeLists.txt Normal file
View file

@ -0,0 +1,37 @@
cmake_minimum_required(VERSION 3.9)
set(VERSION "1.0.1")
set(RELEASE, 1)
set(PACKAGE_NAME "mktouch")
set(VENDOR "AA")
set(DESCRIPTION "Make directory's and files at the same time")
set(CPACK_PACKAGE_CONTACT "Ade Attwood")
project(${PACKAGE_NAME})
add_subdirectory (src)
add_executable(mktouch ./src/App.cpp
./src/Cli.cpp
./src/main.cpp)
FIND_PACKAGE(Boost COMPONENTS program_options filesystem REQUIRED)
INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS})
TARGET_LINK_LIBRARIES(mktouch ${Boost_LIBRARIES})
set(CPACK_PACKAGE_VERSION ${VERSION})
set(CPACK_GENERATOR "DEB;ZIP;TGZ")
set(CPACK_PACKAGE_NAME ${PACKAGE_NAME})
set(CPACK_PACKAGE_RELEASE ${RELEASE})
set(CPACK_PACKAGE_VENDOR ${VENDOR})
set(CPACK_PACKAGING_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX})
set(CPACK_PACKAGE_DESCRIPTION ${DESCRIPTION})
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libboost-program-options1.62.0,libboost-filesystem1.62.0,libboost-system1.62.0,libstdc++6,libgcc1,libc6")
install(TARGETS mktouch DESTINATION bin)
install(DIRECTORY man DESTINATION .)
include(CPack)

6
apt-pkg.txt Normal file
View file

@ -0,0 +1,6 @@
libboost-filesystem1.62.0
libboost-program-options1.62.0
libboost-system1.62.0
libc6
libgcc1
libstdc++6

64
builder Executable file
View file

@ -0,0 +1,64 @@
#!/bin/bash
SRC_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)";
DEBUG_DIR="$SRC_DIR/build/Debug";
RELEASE_DIR="$SRC_DIR/build/Release";
case "$1" in
apt-pkg)
ldd build/Release/mktouch | awk '/=>/{print $(NF-1)}' | while read n; do dpkg-query -S $n | cut -d ":" -f 1; done | uniq | sort > apt-pkg.txt;
;;
debug)
echo "CMAKE --> Debug";
mkdir -p "$DEBUG_DIR";
cd "$DEBUG_DIR";
BUILD_TYPE="Debug";
BUILD="true";
MAKE="true";
;;
release)
echo "CMAKE --> Release";
mkdir -p "$RELEASE_DIR";
cd "$RELEASE_DIR";
BUILD_TYPE="Release";
BUILD="true";
MAKE="true";
;;
package)
echo "CMAKE --> Release";
mkdir -p "$RELEASE_DIR";
cd "$RELEASE_DIR";
BUILD_TYPE="Release";
BUILD="true";
MAKE="true";
PACKAGE="true";
;;
clean)
echo "CMAKE --> Cleaning";
rm -rf "$SRC_DIR/build";
;;
*)
echo "CMAKE --> Build not found";
echo " -- apt-pkg";
echo " -- debug";
echo " -- release";
echo " -- clean";
exit 0;
;;
esac
if [ -n "$BUILD" ]; then
cp -R $SRC_DIR/man $(pwd);
cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE $SRC_DIR;
fi
if [ -n "$MAKE" ]; then
echo "CMAKE --> Make";
make;
fi
if [ -n "$PACKAGE" ]; then
echo "CMAKE --> Package";
make package;
fi

36
man/man1/mktouch.1 Normal file
View file

@ -0,0 +1,36 @@
.TH mkdir 1 "03 feb 2018" "Version 1.0.1" "mktouch man page"
.SH NAME
mktouch \- Make directory's and files at the same time
.SH SYNOPSIS
mktouch
.I file-path file
[options]
.SH DESCRIPTION
Make directory's and files at the same time.
.SH OPTIONS
.PP
-f [ --force ] Force create the file even if it exsits
.PP
-h [ --help ] Show the help message
.PP
-V [ --version ] Display the version number
.SH EXAMPLES
.PP
.B mktouch /my/path
.RE
This command will just create the dir /my/path just like the mkdir command
.PP
.B mktouch /my/path file.txt
.RE
This will make the path like above and then create the file `file.txt` and put it into the directory
.PP
.B mktouch /my/path file.txt -f
.RE
This will do the same as above but if the file already exsits it will be overriten
.SH SEE ALSO
mkdir(1) touch(1)
.SH BUGS
No known bugs.
.SH AUTHOR
Ade Attwood (code@adeattwood.co.uk)

107
src/App.cpp Normal file
View file

@ -0,0 +1,107 @@
#include <iostream>
#include <string>
#include <vector>
#include <boost/program_options.hpp>
#include "App.h"
#include "Cli.h"
App::App() {}
App::App(const App& orig) {}
App::~App() {}
int App::shutDown(int code) {
return code;
}
void App::parseArgs(int argc, char** argv) {
namespace po = boost::program_options;
po::options_description options("Options");
options.add_options()
("force,f", "Force create the file even if it exsits")
("help,h", "Show this messages")
("version,V", "Display the version number");
po::options_description arguments("Arguments");
arguments.add_options()
("file-path", po::value<std::string>(), "The path where to create the file")
("file", po::value<std::string>(), "The file to create");
positionalOptions.add("file-path", 1);
positionalOptions.add("file", 1);
desc.add(arguments).add(options);
po::store(po::command_line_parser(argc, argv).
positional(positionalOptions).
options(desc).
run(),
vm);
po::notify(vm);
}
void App::showHelp() {
std::vector<std::string> parts;
parts.push_back("Usage: ");
parts.push_back(this->name);
size_t N = positionalOptions.max_total_count();
if (N == std::numeric_limits<unsigned>::max()) {
std::vector<std::string> args = this->_getUnlimitedPositionalArgs(positionalOptions);
parts.insert(parts.end(), args.begin(), args.end());
} else {
for(size_t i = 0; i < N; ++i) {
parts.push_back(positionalOptions.name_for_position(i));
}
}
if (desc.options().size() > 0) {
parts.push_back("[options]");
}
std::ostringstream oss;
std::copy(parts.begin(), parts.end(), std::ostream_iterator<std::string>(oss, " "));
oss << '\n' << desc;
std::cout << Cli::style(oss.str());
}
std::vector<std::string> App::_getUnlimitedPositionalArgs(const po::positional_options_description& p)
{
assert(p.max_total_count() == std::numeric_limits<unsigned>::max());
std::vector<std::string> parts;
const int MAX = 1000;
std::string last = p.name_for_position(MAX);
for (size_t i = 0; true; ++i) {
std::string cur = p.name_for_position(i);
if (cur == last) {
parts.push_back(cur);
parts.push_back('[' + cur + ']');
parts.push_back("...");
return parts;
}
parts.push_back(cur);
}
return parts; // never get here
}
void App::showVersion() {
std::cout << "Version: " << this->version << std::endl;
}
bool App::hasOption(std::string name) {
return vm.count(name);
}
po::variable_value App::getOption(std::string name) {
return vm[name];
}

39
src/App.h Normal file
View file

@ -0,0 +1,39 @@
#ifndef APP_H
#define APP_H
#include <iostream>
#include <string>
#include <vector>
#include <boost/program_options.hpp>
namespace po = boost::program_options;
class App {
po::variables_map vm;
po::options_description desc;
po::positional_options_description positionalOptions;
public:
std::string version = "1.0.1";
std::string name = "mktouch";
App();
App(const App& orig);
virtual ~App();
void parseArgs(int argc, char** argv);
void showHelp();
void showVersion();
bool hasOption(std::string name);
int shutDown(int code);
po::variable_value getOption(std::string name);
private:
std::vector<std::string> _getUnlimitedPositionalArgs(const po::positional_options_description& p);
};
#endif /* APP_H */

0
src/CMakeLists.txt Normal file
View file

119
src/Cli.cpp Normal file
View file

@ -0,0 +1,119 @@
#include <iostream>
#include <string>
#include <map>
#include "Cli.h"
Cli::Cli() {}
Cli::Cli(const Cli& orig) {}
Cli::~Cli() {}
std::string Cli::style(std::string string) {
Cli::replace(string, "{{eol}}", "\n");
Cli::replace(string, "{{", "\e[");
Cli::replace(string, "}}", "m");
Cli::replace(string, "cli_fg_red", "31");
Cli::replace(string, "cli_fg_default", "39");
Cli::replace(string, "cli_fg_green", "32");
Cli::replace(string, "cli_fg_yellow", "33");
Cli::replace(string, "cli_fg_blue", "34");
Cli::replace(string, "cli_fg_white", "97");
Cli::replace(string, "cli_fg_black", "30");
Cli::replace(string, "cli_bg_red", "41");
Cli::replace(string, "cli_bg_default", "49");
Cli::replace(string, "cli_bg_green", "42");
Cli::replace(string, "cli_bg_yellow", "43");
Cli::replace(string, "cli_bg_blue", "44");
Cli::replace(string, "cli_bg_white", "107");
Cli::replace(string, "cli_bg_black", "40");
Cli::replace(string, "cli_reset_normal", "0");
Cli::replace(string, "cli_reset_bold", "21");
Cli::replace(string, "cli_reset_dim", "22");
Cli::replace(string, "cli_reset_underline", "24");
Cli::replace(string, "cli_reset_blink", "25");
Cli::replace(string, "cli_reset_invert", "27");
Cli::replace(string, "cli_reset_hidden", "28");
Cli::replace(string, "cli_normal", "0");
Cli::replace(string, "cli_bold", "1");
Cli::replace(string, "cli_dim", "2");
Cli::replace(string, "cli_underline", "4");
Cli::replace(string, "cli_blink", "5");
Cli::replace(string, "cli_invert", "7");
Cli::replace(string, "cli_hidden", "8");
return string;
}
bool Cli::replace(std::string& str, const std::string& from, const std::string& to) {
if(from.empty()) {
return false;
}
size_t start_pos = 0;
while((start_pos = str.find(from, start_pos)) != std::string::npos) {
str.replace(start_pos, from.length(), to);
start_pos += to.length();
}
return true;
}
void Cli::out(std::string output) {
std::cout << Cli::style(output);
}
void Cli::hideCursor() {
Cli::out("\033[?25l");
}
void Cli::showCursor() {
Cli::out("\033[?25h");
}
void Cli::clearScreen() {
Cli::out("\033[2J");
}
void Cli::clearLine() {
Cli::out("\033[2K");
}
std::string Cli::in() {
std::string out;
std::cin >> out;
return out;
}
std::string Cli::readLine(std::string question) {
Cli::out(question);
return Cli::in();
}
int Cli::askQuestion(std::string question, std::map <int, std::string> questionOptions) {
question += "{{eol}}";
for (const auto& kv : questionOptions) {
question += "[" + std::to_string(kv.first) + "] " + kv.second + "{{eol}}";
}
std::string out;
while (out.empty()) {
std::string answer = Cli::readLine(question);
if (questionOptions.find(std::stoi(answer)) == questionOptions.end()) {
Cli::out("Invalid option{{eol}}");
} else {
out = answer;
}
}
return std::stoi(out);
}

31
src/Cli.h Normal file
View file

@ -0,0 +1,31 @@
#ifndef CLI_H
#define CLI_H
#include <iostream>
#include <string>
#include <map>
class Cli {
public:
Cli();
Cli(const Cli& orig);
virtual ~Cli();
static void out(std::string output);
static std::string in();
static void hideCursor();
static void showCursor();
static void clearScreen();
static void clearLine();
static std::string readLine(std::string question);
static int askQuestion(std::string qustion, std::map < int, std::string >);
static std::string style(std::string string);
private:
static bool replace(std::string& str, const std::string& from, const std::string& to);
};
#endif /* CLI_H */

59
src/main.cpp Normal file
View file

@ -0,0 +1,59 @@
#include <iostream>
#include <string>
#include <map>
#include <boost/filesystem.hpp>
#include "App.h"
#include "Cli.h"
namespace fs = boost::filesystem;
namespace {
const size_t SUCCESS = 0;
const size_t ERROR = 1;
const size_t UNHANDLED_ERROR = 2;
} // namespace
int main(int argc, char** argv) {
App app;
try {
app.parseArgs(argc, argv);
} catch(std::exception& E) {
std::cout << "ERROR: " << E.what() << std::endl;
return app.shutDown(UNHANDLED_ERROR);
}
if (app.hasOption("help")) {
app.showHelp();
return app.shutDown(SUCCESS);
}
if (app.hasOption("version")) {
app.showVersion();
return app.shutDown(SUCCESS);
}
if (!app.hasOption("file-path")) {
app.showHelp();
return app.shutDown(ERROR);
}
std::string filePath = app.getOption("file-path").as<std::string>();
fs::create_directories(filePath);
if (app.hasOption("file")) {
std::string file = filePath + "/" + app.getOption("file").as<std::string>();
if (!app.hasOption("force") && fs::exists(file)) {
std::cout << "ERROR: " << file << " already exists" << std::endl;
return app.shutDown(ERROR);
}
std::ofstream outfile (file);
outfile.close();
}
return app.shutDown(SUCCESS);
};