Created
September 18, 2015 23:11
-
-
Save hosaka/c0da35282f343e9dcf60 to your computer and use it in GitHub Desktop.
Create workspace file for sublime text from template with options for ctags and cscope generation.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! /usr/bin/env python | |
# | |
# TODO: | |
# - Separate ctags from sublime function | |
# - Predictable template location | |
# - Generate template if none found | |
# - Total size of cscope files | |
# - Custom exclude folders and more project flexebility for subl/cscope/ctags | |
# perhaps a file list with ignored folders used by all functions | |
# - Remove building functions, too project specific | |
# | |
# Script to setup the development workspace for the software project folder | |
# and assist with building the code. Read everything about the commands by | |
# using -h/--help flag. | |
# | |
# The script will prepare the dev environment for Sublime Text 3. | |
# All the folders you need to work on your software unit according to what is | |
# set in the template.sublime-project file will be included or excluded. | |
# Modify this file according to what you're working with | |
# | |
# This will create the *.sublime-project file and place it under the root | |
# directory of a created workspace. To make use of this feature you need: | |
# sublime text : http://www.sublimetext.com/ | |
# template file : template.sublime-project | |
# | |
# The ctags database can also be built if ctags is installed excluding the | |
# unnecessary folders and placed in the root project folder to enable IDE-like | |
# Ctrl+Click definition navigation. To make use of the ctags generated file | |
# you need: | |
# ctags : http://ctags.sourceforge.net/ | |
# sublime addon : https://github.com/SublimeText/CTags | |
# | |
# To make use of more advanced navigation, for example list callers, list | |
# calling functions and flexible symbol look up, a cscope file can be generated | |
# To use the scope files in your project you need: | |
# cscope : http://cscope.sourceforge.net/ | |
# sublime addon : https://github.com/ameyp/CscopeSublime | |
# | |
############################ DEPRECATED FUNCTIONS ############################# | |
# Remote building on windows via pstools is no longer supported | |
import os | |
import argparse | |
import subprocess | |
__author__ = "alex-march" | |
__version__ = "0.1.0" | |
APP_TITLE = "envmake" | |
APP_ROOT = os.path.realpath(os.path.dirname(__file__)) | |
BUILD_SCRIPT_PATH = "/path/to/builddir" | |
BUILD_SCRIPT_FNAME = "build.py" | |
BUILD_LAST_FNAME = ".last_build" | |
class EnvBuilder(): | |
# project directory, also acts as a project name | |
proj_dir = "" | |
# full path the project | |
proj_path = "" | |
def __init__(self): | |
self.args = self.parse_args() | |
# retain the given user path | |
self.proj_dir = self.args.project | |
# set the full build path | |
self.proj_path = os.path.join(os.getcwd(), self.proj_dir) | |
# check if project folder exists | |
if not os.path.isdir(self.proj_path): | |
print(APP_TITLE + ": " + self.proj_path + " is not a valid path") | |
return | |
# generate the sublime files and ctags if necessary | |
if self.args.action in "subl": | |
gen = WorkspaceGenerator() | |
gen.gen_sublime(self.proj_path, self.proj_dir, self.args.ctags) | |
# gen cscope | |
if self.args.cscope: | |
gen.gen_cscope(self.proj_dir) | |
# TODO: gen ctags outside of gen_sublime function | |
if self.args.ctags: | |
# gen.gen_ctags(self.proj_dir) | |
pass | |
# run build | |
else: | |
self.run_build() | |
def parse_args(self): | |
# set up the parser | |
parser = argparse.ArgumentParser(prog=APP_TITLE, description="available commands description") | |
subparser = parser.add_subparsers(title="available commands", help="build and create environment") | |
# project building | |
build_parser = subparser.add_parser("build", help="run the build system") | |
build_parser.add_argument("client", type=str, help="build client") | |
build_parser.add_argument("version", type=str, help="build bersion") | |
build_parser.add_argument("-k", "--keep_going", action="store_true", help="don't stop on error when building") | |
build_parser.add_argument("-j", "--jobs", type=int, help="run this amount of simultaneous jobs") | |
build_parser.add_argument("-n", "--no_last", action="store_true", help="do not store.last_build file") | |
# just run last build | |
subl_parser = subparser.add_parser("last", help="re-run the last build command in that folder") | |
subl_parser.set_defaults(action="last") | |
# envoronment setup | |
subl_parser = subparser.add_parser("subl", help="create sublime project files") | |
subl_parser.add_argument("-t", "--ctags", action="store_true", help="generate ctags index files") | |
subl_parser.add_argument("-s", "--cscope", action="store_true", help="generate cscope index files") | |
subl_parser.set_defaults(action="subl") | |
# common arguments | |
parser.add_argument("project", type=str, help="relative or full path to project") | |
return parser.parse_args() | |
def run_build(self): | |
# accumulate the build command | |
build_cmd = [] | |
window_title = "building: {} version: {}" | |
# if this is a re-run of the last build, try to read the .last_build file | |
if self.args.action in "last": | |
# try to load the last build command | |
try: | |
with open(self.proj_path + "/" + BUILD_LAST_FNAME, "r") as lastfile: | |
# read only one line, ignore the rest of the file | |
build_cmd = lastfile.readline() | |
build_cmd = build_cmd.split(' ') | |
window_title = window_title.format(build_cmd[2], build_cmd[4]) | |
except IOError: | |
# no last build file, run without one | |
print(APP_TITLE + ": no last build file, run new build to make one") | |
return | |
# this is a new build, make a new build command from the given arguments | |
else: | |
build_cmd = [BUILD_SCRIPT_FNAME, self.args.client, "-v", self.args.version] | |
if self.args.keep_going: | |
build_cmd.append("bparams=-k") | |
if self.args.jobs: | |
build_cmd.append("-j " + str(self.args.jobs)) | |
window_title = window_title.format(self.args.client, self.args.version) | |
print(build_cmd) | |
# build directory | |
build_dir = "{}/{}".format(self.build_build_path, BUILD_SCRIPT_PATH) | |
# descend into the build/ms directory and launch the build_clinet.py | |
try: | |
print(APP_TITLE + ": building in " + build_dir) | |
# set title, subproc way doesn't work | |
os.system("title {}: {} path: {}".format(APP_TITLE, window_title, self.build_build_path)) | |
# run the build command | |
subprocess.call(build_cmd, cwd=build_dir) | |
print(APP_TITLE + ": finished build") | |
except OSError: | |
print(APP_TITLE + ": build script not found") | |
finally: | |
# store last build command unless no_last flag has been set | |
if not self.args.no_last: | |
try: | |
with open(self.build_build_path + "/" + BUILD_LAST_FNAME, "w") as lastfile: | |
lastfile.write(" ".join(str(item) for item in build_cmd)) | |
except IOError: | |
# no last build file | |
print(APP_TITLE + ": cannot write last build file, check permissions") | |
class WorkspaceGenerator(): | |
# sublime project | |
subl_template = "template" | |
subl_proj_suf = ".sublime-project" | |
# ctags | |
ctags_exec = "ctags" | |
ctags_fname = ".tags" | |
# ctags_sorted_fname = ".tags_sorted_by_file" | |
ctags_exclude_dirs = [] | |
# cscope | |
cscope_exec = "cscope" | |
cscope_fname = "cscope.out" | |
# cscope_include_dirs = [] | |
def __init__(self): | |
pass | |
def gen_cscope (self, folder): | |
# cscope execute flags | |
# -R : recurse into directories | |
# -b : build the cross reference only | |
# -q : fast symbol lookup via inverted index (2 more files created) | |
# -k : kernel mode, turn off default include dir (/usr/include) | |
# -f : output file, defaults to cscope.out | |
cscope_cmd = [self.cscope_exec, "-R", "-b", "-q"] | |
# directories and outfile | |
cscope_dir = folder | |
cscope_outfile = os.path.join(cscope_dir, self.cscope_fname) | |
# stack include directories | |
# for fold in self.cscope_include_dirs: | |
# ctags_cmd.append("-I " + fold + " ") | |
# del fold | |
# launch cscope and save the scope file in the project directory | |
print(APP_TITLE + ": building cscope in project folder, be patient...") | |
try: | |
subprocess.Popen(cscope_cmd, cwd=cscope_dir).wait() | |
print(APP_TITLE + ": built in " + cscope_outfile + " ({} KB)".format( | |
os.path.getsize(cscope_outfile)/1024) | |
) | |
except OSError: | |
print(APP_TITLE + ": cscope executable not found, skipping...") | |
return | |
def gen_ctags(self, folder): | |
# ctags execute flags | |
# -R : recurse into directories | |
# -f : output filename | |
ctags_cmd = [self.ctags_exec, "-R", "-f " + self.ctags_fname] | |
ctags_dir = folder | |
ctags_outfile = os.path.join(ctags_dir, self.ctags_fname) | |
# stack all the exclude directories, just like in the sublime project | |
# if not self.ctags_exclude_dirs: | |
# for fold in self.ctags_exclude_dirs: | |
# ctags_cmd.append("--exclude=" + fold) | |
# del fold | |
# launch ctags and save the tags file in the project directory | |
print(APP_TITLE + ": building ctags in project folder, be patient...") | |
try: | |
subprocess.Popen(ctags_cmd, cwd=ctags_dir).wait() | |
print(APP_TITLE + ": built in " + ctags_outfile + " ({} KB)".format( | |
os.path.getsize(ctags_outfile)/1024) | |
) | |
except OSError: | |
print(APP_TITLE + ": ctags executable not found, skipping...") | |
return | |
def gen_sublime(self, folder, name, prepare_ctags): | |
# copy files to the project root | |
import json | |
# read the template file | |
try: | |
with open( | |
os.path.join(APP_ROOT, self.subl_template + self.subl_proj_suf) | |
) as infile: | |
# load template | |
proj_conf = json.load(infile) | |
except IOError: | |
# no template file | |
print(APP_TITLE + ": no template.sublime-project file, not making a new one") | |
return | |
# use the fields given on the command line | |
proj_conf["folders"][0]["name"] = name | |
proj_conf["folders"][0]["path"] = "." | |
# write the project file to the project path | |
outfile_name = os.path.join(folder, name + self.subl_proj_suf) | |
try: | |
with open(outfile_name, 'w') as outfile: | |
json.dump(proj_conf, outfile, sort_keys=True, indent=4) | |
except IOError: | |
print(APP_TITLE + ": cannot write project file in: " + outfile_name) | |
print(APP_TITLE + ": check permissions or project folder name") | |
return | |
print(APP_TITLE + ": created " + outfile_name) | |
# collect the exclude folders for ctags generation | |
if prepare_ctags: | |
for fold in proj_conf["folders"][0]["folder_exclude_patterns"]: | |
self.ctags_exclude_dirs.append(fold.encode("utf-8")) | |
del fold | |
# generate ctags | |
self.gen_ctags(folder) | |
if __name__ == "__main__": | |
builder = EnvBuilder() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Show hidden characters
{ | |
"settings": | |
{ | |
"tab_size": 4, | |
"translate_tabs_to_spaces": true, | |
"default_line_ending": "unix" | |
}, | |
"folders": | |
[ | |
{ | |
"name": "", | |
"path": "", | |
"file_include_patterns": [ | |
"" | |
], | |
"file_exclude_patterns": [ | |
".*", | |
"*.sublime*" | |
"cscope.*" | |
], | |
"folder_exclude_patterns": | |
[ | |
"" | |
] | |
} | |
] | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment