Ejemplo n.º 1
0
 def __init__(self, config):
     """
     Initialize the parse with the current watson config.
     """
     # Identify method entry.
     debug_print(get_current_method_signature())
     self.config = config
Ejemplo n.º 2
0
    def create_conf(self):
        """
        Watson config creater
        Copies default config from /assets/defaultConf to the current directory
        """
        # Identify method entry
        debug_print(get_current_method_signature())

        # Get the absolute path to the directory this source is in.
        s = os.path.abspath(sys.modules[Config.__module__].__file__)
        # [review] - regex uses (.?)+ to grab anything after watson (optional), better regex?
        full_path = re.sub(r'/watson(.?)+', '', s) + "/assets/defaultConf"

        # Check to make sure we can access the default file
        if not FS.check_file(full_path):
            print "Unable to open %s" % full_path
            print "Cannot create default, exiting..."
            return False
        else:
            # Open default config file in read mode and read into temp
            input_file = open(full_path, 'r')
            default = input_file.read()

            # Open rc file in current directory in write mode and write default
            output_file = open(self.rc_file, 'w')
            output_file.write(default)

            # Close both default and new rc files
            input_file.close()
            output_file.close()

            debug_print("Successfully wrote defaultConf to current directory")
            return True
Ejemplo n.º 3
0
    def create_conf(self):
        """
        Watson config creater
        Copies default config from /assets/defaultConf to the current directory
        """
        # Identify method entry
        debug_print(get_current_method_signature())

        # Get the absolute path to the directory this source is in.
        s = os.path.abspath(sys.modules[Config.__module__].__file__)
        # [review] - regex uses (.?)+ to grab anything after watson (optional), better regex?
        full_path = re.sub(r'/watson(.?)+', '', s) + "/assets/defaultConf"

        # Check to make sure we can access the default file
        if not FS.check_file(full_path):
            print "Unable to open %s" % full_path
            print "Cannot create default, exiting..."
            return False
        else:
            # Open default config file in read mode and read into temp
            input_file = open(full_path, 'r')
            default = input_file.read()

            # Open rc file in current directory in write mode and write default
            output_file = open(self.rc_file, 'w')
            output_file.write(default)

            # Close both default and new rc files
            input_file.close()
            output_file.close()

            debug_print("Successfully wrote defaultConf to current directory")
            return True
Ejemplo n.º 4
0
 def parse_dir(self, dir, depth):
     """
     Parse through specified directory and find all subdirs and files.
     """
     # Identify method entry.
     debug_print(get_current_method_signature())
     return NotImplemented
Ejemplo n.º 5
0
    def get_comment_type(self, filename):
        """
        Get comment syntax for given file.
        """
        # Identify method entry
        debug_print(get_current_method_signature())

        ext = {
            'cpp'    : ['//', '/*'],        # C++
            'cc'     : ['//', '/*'],
            'hpp'    : ['//', '/*'],
            'c'      : ['//', '/*'],        # C
            'h'      : ['//', '/*'],
            'java'   : ['//', '/*', '/**'], # Java
            'class'  : ['//', '/*', '/**'],
            'cs'     : ['//', '/*'],        # C#
            'js'     : ['//', '/*'],        # JavaScript
            'php'    : ['//', '/*', '#'],   # PHP
            'm'      : ['//', '/*'],        # ObjectiveC
            'mm'     : ['//', '/*'],
            'go'     : ['//', '/*'],        # Go(lang)
            'scala'  : ['//', '/*'],        # Scala
            'erl'    : ['%%', '%'],         # Erlang
            'f'      : ['!'],               # Fortran
            'f90'    : ['!'],               # Fortran
            'F'      : ['!'],               # Fortran
            'F90'    : ['!'],               # Fortran
            'hs'     : ['--'],              # Haskell
            'sh'     : ['#'],               # Bash
            'rb'     : ['#'],               # Ruby
            'pl'     : ['#'],               # Perl
            'pm'     : ['#'],
            't'      : ['#'],
            'py'     : ['#'],               # Python
            'coffee' : ['#'],               # CoffeeScript
            'zsh'    : ['#'],               # Zsh
            'clj'    : [';;'],              # Clojure
            'sql'    : ['---', '//', '#' ], # SQL and PL types
        }

        # Grab the file extension (.something).
        # Check to see whether it is recognized and set comment type.
        # If unrecognized, try to grab the next .something extension.
        # This is to account for file.cpp.1 or file.cpp.bak, ect.

        filename_part_list = filename.split('.')
        for filename_part in reversed(filename_part_list):
            debug_print("Extension .%s" % filename_part)

            if filename_part in ext:
                return ext[filename_part]

        # We didn't find any matches from the filename, return None
        # Deal with what default to use in calling method
        debug_print("Couldn't find any recognized extension type")
        return None
Ejemplo n.º 6
0
    def run(self):
        """
        Parse through configuration and obtain remote info if necessary
        """
        # Identify method entry
        debug_print(get_current_method_signature())

        # check_conf should create if no conf found, exit entirely if can't do either
        if self.check_conf() == False:
            sys.exit(1)

        self.read_conf()
Ejemplo n.º 7
0
    def print_header():
        """
        Standard header print for static call (uses static cprint)
        """
        # Identify method entry
        debug_print(get_current_method_signature())

        # Header
        Printer.cprint('%s------------------------------%s\n' % (BOLD, RESET))
        Printer.cprint('%swatson%s' % (BOLD, RESET))
        Printer.cprint(' - %s%sinline issue manager%s\n' % (BOLD, YELLOW, RESET))
        Printer.cprint('%s------------------------------%s\n\n' % (BOLD, RESET))
Ejemplo n.º 8
0
    def run(self):
        """
        Parse through configuration and obtain remote info if necessary
        """
        # Identify method entry
        debug_print(get_current_method_signature())

        # check_conf should create if no conf found, exit entirely if can't do either
        if self.check_conf() == False:
            sys.exit(1)

        self.read_conf()
Ejemplo n.º 9
0
    def version():
        """
        Print version information about watson
        """
        # Identify method entry
        debug_print(get_current_method_signature())

        print 'watson v%s' % VERSION
        print 'Copyright (c) 2012-2013 goosecode labs'
        print 'Licensed under MIT, see LICENSE for details\n'
        print 'Written by mleonard87, see <http://goosecode.com/projects/watson>'

        return True
Ejemplo n.º 10
0
    def version():
        """
        Print version information about watson
        """
        # Identify method entry
        debug_print(get_current_method_signature())

        print 'watson v%s' % VERSION
        print 'Copyright (c) 2012-2013 goosecode labs'
        print 'Licensed under MIT, see LICENSE for details\n'
        print 'Written by mleonard87, see <http://goosecode.com/projects/watson>'

        return True
Ejemplo n.º 11
0
    def run(self):
        """
        Begins parsing of files / dirs specified in the initial dir/file lists.
        """
        # Identify method entry.
        debug_print(get_current_method_signature())

        # Go through all files added for CL (sort them first).
        # If empty, sort and each will do nothing, no errors.
        completed_dirs = []
        completed_files = []
        if self.config.cl_entry_set:
            for f in self.config.file_list.sort():
                completed_files.append(parse_file(f))
Ejemplo n.º 12
0
    def cprint (msg="", color=""):
        """
        Custom color print for static call (only writes to STDOUT)
        """
        # Identify method entry
        debug_print(get_current_method_signature())

        if isinstance(color, str):
            debug_print('Custom color specified for cprint')
            sys.stdout.write(color)
        elif (256 <= color <= 0):
            debug_print('No or Default color specified for cprint')
            sys.stdout.write('\033[38;5;%sm' % color)

        sys.stdout.write(msg)
Ejemplo n.º 13
0
    def check_dir(dirname):
        """
        Check if directory exists and can be opened
        """
        # Identify method entry
        debug_print(get_current_method_signature())

        # Error check for input
        if len(dirname) == 0:
            debug_print( "No directory specified")
            return False

        if os.path.isdir(dirname):
            debug_print("%s exists and opened succesfully" % dirname)
            return True
        else:
            debug_print("Could not open %s, skipping" % dirname)
            return False
Ejemplo n.º 14
0
    def check_dir(dirname):
        """
        Check if directory exists and can be opened
        """
        # Identify method entry
        debug_print(get_current_method_signature())

        # Error check for input
        if len(dirname) == 0:
            debug_print("No directory specified")
            return False

        if os.path.isdir(dirname):
            debug_print("%s exists and opened succesfully" % dirname)
            return True
        else:
            debug_print("Could not open %s, skipping" % dirname)
            return False
Ejemplo n.º 15
0
    def check_file(filename):
        """
        Check if file exists and can be opened
        """
        # Identify method entry
        debug_print(get_current_method_signature())

        # Error check for input
        if len(filename) == 0:
            debug_print("No file specified")
            return False

        # Check if file can be opened
        if os.access(filename, os.R_OK):
            debug_print("%s exists and opened successfully" % filename)
            return True
        else:
            debug_print("Could not open %s, skipping" % filename)
            return False
Ejemplo n.º 16
0
    def check_file(filename):
        """
        Check if file exists and can be opened
        """
        # Identify method entry
        debug_print(get_current_method_signature())

        # Error check for input
        if len(filename) == 0:
            debug_print("No file specified")
            return False

        # Check if file can be opened
        if os.access(filename, os.R_OK):
            debug_print("%s exists and opened successfully" % filename)
            return True
        else:
            debug_print("Could not open %s, skipping" % filename)
            return False            
Ejemplo n.º 17
0
    def check_conf(self):
        """
        Check for config file in directory of execution
        Should have individual .rc for each dir that watson is used in
        This allows you to keep different preferences for different projects
        Create conf (with #create_conf) if not found
        """
        # Identify method entry
        debug_print(get_current_method_signature())

        # Check for .rc
        # If one doesn't exist, create default one with create_conf method
        if os.path.exists(self.rc_file):
            debug_print("%s found" % self.rc_file)
            return True
        else:
            debug_print("%s not found" % self.rc_file)
            debug_print("Creating default %s" % self.rc_file)

            # Create default .rc and return create_conf (True if created, False
            # if not)
            return self.create_conf()
Ejemplo n.º 18
0
    def check_conf(self):
        """
        Check for config file in directory of execution
        Should have individual .rc for each dir that watson is used in
        This allows you to keep different preferences for different projects
        Create conf (with #create_conf) if not found
        """
        # Identify method entry
        debug_print(get_current_method_signature())

        # Check for .rc
        # If one doesn't exist, create default one with create_conf method
        if os.path.exists(self.rc_file):
            debug_print("%s found" % self.rc_file)
            return True
        else:
            debug_print("%s not found" % self.rc_file)
            debug_print("Creating default %s" % self.rc_file)

            # Create default .rc and return create_conf (True if created, False
            # if not)
            return self.create_conf()            
Ejemplo n.º 19
0
 def set_context(args):
     """
     Set context_depth parameter in config
     """
     # Identify method entry
     debug_print(get_current_method_signature())
Ejemplo n.º 20
0
    def parse_file(self, filename):
        """
        Parse through individual files looking for issue tags, then generate
        formatted issue hash.
        """
        # Identify method entry.
        debug_print(get_current_method_signature())

        relative_path = filename
        absolute_path = os.path.abspath(filename)

        # Error check on input, use input filename to make sure relative path is
        # correct.
        if FS.check_file(relative_path):
            debug_print("Opened %s for parsing." % absolute_path)
            debug_print("Short path: %s" % relative_path)
        else:
            print "Unable to open %s, exiting" % relative_path
            # [review] - do I really want to return None here? what consumes this?
            return None 

        # Get file extension and set corresponding comment type.
        comment_type = self.get_comment_type(relative_path)
        if not comment_type:
            debug_print("Using default (#) comment type.")
            comment_type = '#'

        # Open file and read in entire thing into an array.
        # Use an array so we can look ahead when creating issues later.
        # [review] - Not sure if explicit file close is required here.
        data = []
        file_to_parse = open(absolute_path, 'r')
        for line in file_to_parse:
            data.append(line.strip())

        # Initialize issue list hash
        issue_list = {}
        issue_list['relative_path'] = relative_path
        issue_list['absolute_path'] = absolute_path
        issue_list['has_issues'] = False
        for tag in self.config.tag_list:
            debug_print("Create array named %s" % tag)
            issue_list[tag] = []

        
        # For each comment type allowed for the file type convert it into a
        # string that can be used in a regex.
        comment_type_re_str = '|'.join('(' + re.escape(ext) + ')' for ext in comment_type)
        issue_re = re.compile(r'^(%s)+?\s+\[(?P<tag_name>\w+)\]\s+-\s+(?P<title_text>.+)' % comment_type_re_str)
        # Loop through all array elements (lines in file) and look for issues
        for i, line in enumerate(data):
            # Find any comment line with [tag] - text (any combination of space
            # and # acceptable).
            # Using if match to stay consistent (with config.py) see there for 
            # explanation of why I do this (not a good good one persay...)
            mtch = issue_re.match(line.strip())
            if not mtch:
                debug_print("No valid tag found in line, skipping")
                continue

            tag = mtch.group('tag_name')

            if tag not in self.config.tag_list:
                Printer.print_status('!', RED)
                print "Unknown tag [%s] found, ignoring" % tag
                print "      You might want to include it in you RC or with the -t/--tags flag"
                continue

            # Found a valid match (with recognized tag).
            # Set flag for this issue_list (for_file) to indicate that.
            issue_list['hase_issues'] = True

            title = mtch.group('title_text')
            debug_print("Issue found")
            debug_print("Tag: %s" % tag)
            debug_print("Issue: %s" % title)

            # Create dict for each issue found.
            issue = {}
            issue['line_number'] = i + 1
            issue['title'] = title

            # Grab context of issue specified by Config param (+1 to include issue iteself.)
            issue['context'] = data[i:i + self.config.context_depth + 1]
Ejemplo n.º 21
0
    def update_conf(self, **kwargs):
        """
        Update config file with specified parameters
        Accepts input parameters that should be updated and writes to file
        Selective updating to make bookkeeping easier
        """
        # Identify method entry
        debug_print(get_current_method_signature())

        # Check if RC exists, if not create one.
        if not FS.check_file(self.rc_file):
            print "Unable to open %s, exiting" % self.rc_file
            self.create_conf()
        else:
            debug_print("Opened %s for reading" % self.rc_file)

        # Go through all given params and make sure they are actually config vars
        for param in kwargs:
            if not hasattr(self, param):
                debug_print("%s does not exist in Config" % param)
                debug_print("Check your input(s) to update_conf")

        # Read in currently saved RC and go through it line by line
        # Only update params that were passed to update_conf
        # This allows us to clean up the config file at the same time

        # Open and read rc
        # [review] - Not sure if explicit file close is required here
        rc = open(self.rc_file, 'r').read()
        rc_update_file = open(self.rc_file, 'w')

        # Keep index to print what line we are on
        i = 0

        # Keep track of newlines for prettying up the conf
        nlc = 0
        section = ""

        # Fix line endings so we can support Windows/Linux edited rc files
        rc = re.sub(r'\r\n?', '\n', rc)
        for line in rc.splitlines():
            # Print line for debug purposes
            debug_print("%d: %s" % (i, line))
            i += 1

            # Look for sections and set section var
            mtch = re.match(r'\[(\w+)\]', line)
            if mtch:
                debug_print("Found section %s" % mtch.group(1))
                section = mtch.group(1)

            # Check for newlines
            # If we already have 2 newlines before any actual content, skip
            # This is just to make the RC file output nicer looking
            if line == '\n':
                debug_print("Newline found")
                nlc += 1
                if nlc < 3:
                    debug_print("Less than 3 newlines so far, let it print")
                    rc_update_file.write('%s\n' % line)
            # If the section we are in doesn't match the params passed to update_conf
            # it is safe to write the line over to the new config
            elif not section in kwargs:
                debug_print("Current section NOT a param to update")
                debug_print("Writing to new rc")
                rc_update_file.write('%s\n' % line)

                # Reset newline
                nlc = 0

            debug_print("line: %s" % line)
            debug_print("nlc: %d" % nlc)

        # Make sure there is at least 3 newlines between last section before writing new params
        rc_update_file.write('\n' * (2 - nlc))

        # Now that we have skipped all the things that need to be update, write them in
        for key, value in kwargs.iteritems():
            rc_update_file.write('[%s]\n' % key)
            rc_update_file.write(getattr(self, key))
            rc_update_file.write('\n\n\n')

        rc_update_file.close()
Ejemplo n.º 22
0
    def read_conf(self):
        """
        Read configuration file and populate Config container class
        """
        # Identify method entry
        debug_print(get_current_method_signature())

        debug_print("Reading %s" % self.rc_file)
        if not FS.check_file(self.rc_file):
            print("Unable to open %s, exiting" % self.rc_file)
            return False
        else:
            debug_print("Opened %s for reading" % self.rc_file)

        # Check if system has less for output
        self.use_less = check_less()

        # Add all the standard items to ignorelist
        # This gets added regardless of ignore list specified
        # [review] - Keep *.swp in there?
        # [todo] - Add conditional to @rc_file such that if passed by -f we accept it
        # [todo] - Add current file (watson) to avoid accidentally printing app tags
        self.ignore_list.append("..")
        self.ignore_list.append(self.rc_file)
        self.ignore_list.append(self.tmp_file)

        # Open and read rc
        # [review] - Not sure if explicit file close is required here
        rc = open(self.rc_file, 'r').read()

        debug_print('\n')

        # Create temp section var to keep track of what we are populating in config
        section = ""

        # Keep index to print what line we are on
        i = 0

        # Fix line endings so we can support Windows/Linux edited rc files
        rc = re.sub(r'\r\n?', '\n', rc)

        # Pre-compile the regexes here for performance inside the loops.
        comment_re = re.compile(r'(^#)|(^\n)|(^ *$)')
        section_re = re.compile(r'\[(?P<section_name>\w+)\]')
        dir_re = re.compile(r'^(([\w*]+)?\.?\/?)+')
        tag_re = re.compile(r'(?P<tag_name>\S+)')
        ignores_re = re.compile(r'^(?P<ignore_name>([\w*]+)?\.?\/?)+')

        for line in rc.splitlines():
            debug_print("%d: %s" % (i, line))
            i += 1

            # Ignore full line comments or newlines
            mtch = comment_re.match(line)
            if mtch:
                debug_print("Full line comment or newline found, skipping")
                continue

            # Regex on line to find out if we are in a new [section] of
            # config parameters. If so, store it into section var and move
            # to next line
            mtch = section_re.match(line)
            if mtch:
                debug_print("Found section %s" % mtch.group('section_name'))
                section = mtch.group(1)
                continue

            if section == 'context_depth':
                # No need for regex on context value, command should read this in only as a #
                # strip to get rid of any nonsense
                self.context_depth = line.strip()

            elif section == 'parse_depth':
                # No need for regex on parse value, command should read this in only as a #
                # strip to get rid of any nonsense
                self.parse_depth = line.strip()

            elif section == 'dirs':
                # If self.dir_list or self.file_list wasn't populated by CL args
                # then populate from rc
                # [review] - Populate @dirs/files_list first, then check size instead
                if self.cl_entry_set:
                    debug_print(
                        "Directories or files set from command line ignoring rc [dirs]"
                    )
                    continue

                # Regex to grab directory
                # Substitute trailing / (necessary for later formatting)
                # and push to self.dir_list
                mtch = dir_re.match(line)
                if mtch:
                    # [review] - why doesnt a named group match corrently for this regex?
                    dir_path = mtch.group(0).rstrip('/')
                    self.dir_list.append(dir_path)
                    debug_print("%s added to self.dir_list" % dir_path)

                debug_print("self.dir_list --> %s" % self.dir_list.__str__())

            elif section == 'tags':
                # Same as previous for tags
                # [review] - Populate @tag_list, then check size instead
                if self.cl_tag_set:
                    debug_print(
                        "Tags set from command line, ignoring rc [tags]")
                    continue

                # Same as previous for tags
                # [review] - Need to think about what kind of tags this supports
                # Check compatibility with GitHub + Bitbucket and what makes sense
                # Only supports single word+number tags
                mtch = tag_re.match(line)
                if mtch:
                    tag = mtch.group('tag_name')
                    self.tag_list.append(tag)
                    debug_print("%s added to @tag_list" % tag)

                debug_print("self.tag_list --> %s" % self.tag_list.__str__())

            elif section == 'ignore':
                # Same as previous for ignores
                # [review] - Populate @tag_list, then check size instead
                if self.cl_ignore_set:
                    debug_print(
                        "Ignores set from command line, ignoring rc [ignores]")
                    continue

                # Same as previous for ignores (regex same as dirs)
                # Don't eliminate trailing / because not sure if dir can have
                # same name as file (Linux it can't, but not sure about Win/Mac)
                # [review] - Can Win/Mac have dir + file with same name in same dir?
                mtch = ignores_re.match(line)
                if mtch:
                    # [review] - why doesnt a named group match corrently for this regex?
                    dir_path = mtch.group(0)
                    self.ignore_list.append(dir_path)
                    debug_print("%s added to self.ignore_list" % dir_path)

                debug_print("self.ignore_list --> %s" %
                            self.ignore_list.__str__())

            elif section == 'github_api':
                # No need for regex on API key, GitHub setup should do this properly
                # strip to get rid of any nonsense
                self.github_api = line.string()
                debug_print("GitHub API: %s" % self.github_api)

            elif section == 'github_repo':
                # Same as above
                self.github_repo = line.strip()
                debug_print("GitHub Repo: %s" % self.github_repo)

            elif section == 'bitbucket_api':
                # Same as GitHub parse above
                self.bitbucket_api = line.strip()
                debug_print("Bitbucket API: %s" % self.bitbucket_api)

            elif section == 'bitbucket_repo':
                # Same as GitHub repo parse above
                self.bitbucket_repo = line.strip()
                debug_print("Bitbucket Repo: %s" % self.bitbucket_repo)

            else:
                debug_print("Unknown tag found %s" % section)

        return True
Ejemplo n.º 23
0
    def __init__(self):
        """
        Config initialization method to setup necessary parameters, states, and
        vars
        """
        # Identify method entry
        debug_print(get_current_method_signature())

        # [todo] - Add config options (rc file) for default max depth and context lines

        # List of all files/folders to ignore when parsing
        self.ignore_list = []
        # List of directories to parse
        self.dir_list = []
        # List of all files to parse
        self.file_list = []
        # List of tags to look for when parsing
        self.tag_list = []
        # Number of directories to parse recursively
        self.parse_depth = 0
        # Number of lines of issue context to grab
        self.context_depth = 15

        # Flag for command line setting of file/dir to parse
        self.cl_entry_set = False
        # Flag for command line setting of file/dir to ignore
        self.cl_ignore_set = False
        # Flag for command line setting of tag to parse for
        self.cl_tag_set = False

        # Entries that watson should show
        self.show_type = 'all'

        # Flag for whether less is avaliable to print results
        self.use_less = False
        #Flag for where the config file is located
        self.rc_file = '.watsonrc'
        # Flag for where the temp file for printing is located
        self.tmp_file = '.watsonresults'

        # Flag for whether remote access is avaliable
        self.remote_vaild = False

        # Flag for whether GitHub access is avaliable
        self.github_valid = False
        # GitHub API key generated from Remote::GitHub setup
        self.github_api = ''
        # GitHub repo associated with current directory + watson config
        self.github_repo = ''
        # Hash to hold list of all GitHub issues associated with repo
        # [todo] - What data structure for github_issues is best?
        self.github_issues = None

        # Flag for whether Bitbucket access is avaliable
        self.bitbucket_valid = False
        # Bitbucket API key generated from Remote::Bitbucket setup (username for now)
        self.bitbucket_api = ''
        # Bitbucket password for access until OAuth is implemented for Bitbucket
        self.bitbucket_pw = ''
        # Bitbucket repo associated with current directory + watson config
        self.bitbucket_repo = ''
        # Hash to hold list of all Bitbucket issues associated with repo
        # [todo] - What data structure for bitbucket_issues is best?
        self.bitbucket_issues = None
Ejemplo n.º 24
0
    def __init__(self):
        """
        Config initialization method to setup necessary parameters, states, and
        vars
        """
        # Identify method entry
        debug_print(get_current_method_signature())

        # [todo] - Add config options (rc file) for default max depth and context lines

        # List of all files/folders to ignore when parsing
        self.ignore_list = []
        # List of directories to parse
        self.dir_list = []
        # List of all files to parse
        self.file_list = []
        # List of tags to look for when parsing
        self.tag_list = []
        # Number of directories to parse recursively
        self.parse_depth = 0
        # Number of lines of issue context to grab
        self.context_depth = 15

        # Flag for command line setting of file/dir to parse
        self.cl_entry_set = False
        # Flag for command line setting of file/dir to ignore
        self.cl_ignore_set = False
        # Flag for command line setting of tag to parse for
        self.cl_tag_set = False

        # Entries that watson should show
        self.show_type = 'all'

        # Flag for whether less is avaliable to print results
        self.use_less = False
        #Flag for where the config file is located
        self.rc_file = '.watsonrc'
        # Flag for where the temp file for printing is located
        self.tmp_file = '.watsonresults'

        # Flag for whether remote access is avaliable
        self.remote_vaild = False

        # Flag for whether GitHub access is avaliable
        self.github_valid = False
        # GitHub API key generated from Remote::GitHub setup
        self.github_api = ''
        # GitHub repo associated with current directory + watson config
        self.github_repo = ''
        # Hash to hold list of all GitHub issues associated with repo
        # [todo] - What data structure for github_issues is best?
        self.github_issues = None

        # Flag for whether Bitbucket access is avaliable
        self.bitbucket_valid = False
        # Bitbucket API key generated from Remote::Bitbucket setup (username for now)
        self.bitbucket_api = ''
        # Bitbucket password for access until OAuth is implemented for Bitbucket
        self.bitbucket_pw = ''
        # Bitbucket repo associated with current directory + watson config
        self.bitbucket_repo = ''
        # Hash to hold list of all Bitbucket issues associated with repo
        # [todo] - What data structure for bitbucket_issues is best?
        self.bitbucket_issues = None
Ejemplo n.º 25
0
    def read_conf(self):
        """
        Read configuration file and populate Config container class
        """
        # Identify method entry
        debug_print(get_current_method_signature())


        debug_print("Reading %s" % self.rc_file)
        if not FS.check_file(self.rc_file):
            print ("Unable to open %s, exiting" % self.rc_file)
            return False
        else:
            debug_print("Opened %s for reading" % self.rc_file)

        # Check if system has less for output
        self.use_less = check_less()

        # Add all the standard items to ignorelist
        # This gets added regardless of ignore list specified
        # [review] - Keep *.swp in there?
        # [todo] - Add conditional to @rc_file such that if passed by -f we accept it
        # [todo] - Add current file (watson) to avoid accidentally printing app tags
        self.ignore_list.append("..")
        self.ignore_list.append(self.rc_file)
        self.ignore_list.append(self.tmp_file)

        # Open and read rc
        # [review] - Not sure if explicit file close is required here
        rc = open(self.rc_file, 'r').read()

        debug_print('\n')

        # Create temp section var to keep track of what we are populating in config
        section = ""

        # Keep index to print what line we are on
        i = 0;

        # Fix line endings so we can support Windows/Linux edited rc files
        rc = re.sub(r'\r\n?', '\n', rc)

        # Pre-compile the regexes here for performance inside the loops.
        comment_re = re.compile(r'(^#)|(^\n)|(^ *$)')
        section_re = re.compile(r'\[(?P<section_name>\w+)\]')
        dir_re = re.compile(r'^(([\w*]+)?\.?\/?)+')
        tag_re = re.compile(r'(?P<tag_name>\S+)')
        ignores_re = re.compile(r'^(?P<ignore_name>([\w*]+)?\.?\/?)+')

        for line in rc.splitlines():
            debug_print("%d: %s" % (i, line))
            i += 1

            # Ignore full line comments or newlines
            mtch = comment_re.match(line)
            if mtch:
                debug_print("Full line comment or newline found, skipping")
                continue

            # Regex on line to find out if we are in a new [section] of
            # config parameters. If so, store it into section var and move
            # to next line
            mtch = section_re.match(line)
            if mtch:
                debug_print("Found section %s" % mtch.group('section_name'))
                section = mtch.group(1)
                continue

            if section == 'context_depth':
                # No need for regex on context value, command should read this in only as a #
                # strip to get rid of any nonsense
                self.context_depth = line.strip()

            elif section == 'parse_depth':
                # No need for regex on parse value, command should read this in only as a #
                # strip to get rid of any nonsense
                self.parse_depth = line.strip()

            elif section == 'dirs':
                # If self.dir_list or self.file_list wasn't populated by CL args
                # then populate from rc
                # [review] - Populate @dirs/files_list first, then check size instead
                if self.cl_entry_set:
                    debug_print("Directories or files set from command line ignoring rc [dirs]")
                    continue

                # Regex to grab directory
                # Substitute trailing / (necessary for later formatting)
                # and push to self.dir_list
                mtch = dir_re.match(line)
                if mtch:
                    # [review] - why doesnt a named group match corrently for this regex?
                    dir_path = mtch.group(0).rstrip('/')
                    self.dir_list.append(dir_path)
                    debug_print("%s added to self.dir_list" % dir_path)

                debug_print("self.dir_list --> %s" % self.dir_list.__str__())

            elif section == 'tags':
                # Same as previous for tags
                # [review] - Populate @tag_list, then check size instead
                if self.cl_tag_set:
                    debug_print("Tags set from command line, ignoring rc [tags]")
                    continue

                # Same as previous for tags
                # [review] - Need to think about what kind of tags this supports
                # Check compatibility with GitHub + Bitbucket and what makes sense
                # Only supports single word+number tags
                mtch = tag_re.match(line)
                if mtch:
                    tag = mtch.group('tag_name')
                    self.tag_list.append(tag)
                    debug_print("%s added to @tag_list" % tag)

                debug_print("self.tag_list --> %s" % self.tag_list.__str__())

            elif section == 'ignore':
                # Same as previous for ignores
                # [review] - Populate @tag_list, then check size instead
                if self.cl_ignore_set:
                    debug_print("Ignores set from command line, ignoring rc [ignores]")
                    continue

                # Same as previous for ignores (regex same as dirs)
                # Don't eliminate trailing / because not sure if dir can have
                # same name as file (Linux it can't, but not sure about Win/Mac)
                # [review] - Can Win/Mac have dir + file with same name in same dir?
                mtch = ignores_re.match(line)
                if mtch:
                    # [review] - why doesnt a named group match corrently for this regex?
                    dir_path = mtch.group(0)
                    self.ignore_list.append(dir_path)
                    debug_print("%s added to self.ignore_list" % dir_path)

                debug_print("self.ignore_list --> %s" % self.ignore_list.__str__())

            elif section == 'github_api':
                # No need for regex on API key, GitHub setup should do this properly
                # strip to get rid of any nonsense
                self.github_api = line.string()
                debug_print("GitHub API: %s" % self.github_api)

            elif section == 'github_repo':
                # Same as above
                self.github_repo = line.strip()
                debug_print("GitHub Repo: %s" % self.github_repo)

            elif section == 'bitbucket_api':
                # Same as GitHub parse above
                self.bitbucket_api = line.strip()
                debug_print("Bitbucket API: %s" % self.bitbucket_api)

            elif section == 'bitbucket_repo':
                # Same as GitHub repo parse above
                self.bitbucket_repo = line.strip()
                debug_print("Bitbucket Repo: %s" % self.bitbucket_repo)

            else:
                debug_print("Unknown tag found %s" % section)

        return True
Ejemplo n.º 26
0
    def update_conf(self, **kwargs):
        """
        Update config file with specified parameters
        Accepts input parameters that should be updated and writes to file
        Selective updating to make bookkeeping easier
        """
        # Identify method entry
        debug_print(get_current_method_signature())

        # Check if RC exists, if not create one.
        if not FS.check_file(self.rc_file):
            print "Unable to open %s, exiting" % self.rc_file
            self.create_conf()
        else:
            debug_print("Opened %s for reading" % self.rc_file)

        # Go through all given params and make sure they are actually config vars
        for param in kwargs:
            if not hasattr(self, param):
                debug_print("%s does not exist in Config" % param)
                debug_print("Check your input(s) to update_conf")

        # Read in currently saved RC and go through it line by line
        # Only update params that were passed to update_conf
        # This allows us to clean up the config file at the same time

        # Open and read rc
        # [review] - Not sure if explicit file close is required here
        rc = open(self.rc_file, 'r').read()
        rc_update_file = open(self.rc_file, 'w')

        # Keep index to print what line we are on
        i = 0;

        # Keep track of newlines for prettying up the conf
        nlc = 0
        section = ""

        # Fix line endings so we can support Windows/Linux edited rc files
        rc = re.sub(r'\r\n?', '\n', rc)
        for line in rc.splitlines():
            # Print line for debug purposes
            debug_print("%d: %s" % (i, line))
            i += 1

            # Look for sections and set section var
            mtch = re.match(r'\[(\w+)\]', line)
            if mtch:
                debug_print("Found section %s" % mtch.group(1))
                section = mtch.group(1)

            # Check for newlines
            # If we already have 2 newlines before any actual content, skip
            # This is just to make the RC file output nicer looking
            if line == '\n':
                debug_print("Newline found")
                nlc += 1
                if nlc < 3:
                    debug_print("Less than 3 newlines so far, let it print")
                    rc_update_file.write('%s\n' % line)
            # If the section we are in doesn't match the params passed to update_conf
            # it is safe to write the line over to the new config
            elif not section in kwargs:
                debug_print("Current section NOT a param to update")
                debug_print("Writing to new rc")
                rc_update_file.write('%s\n' % line)

                # Reset newline
                nlc = 0

            debug_print("line: %s" % line)
            debug_print("nlc: %d" % nlc)

        # Make sure there is at least 3 newlines between last section before writing new params
        rc_update_file.write('\n' * (2 - nlc))

        # Now that we have skipped all the things that need to be update, write them in
        for key, value in kwargs.iteritems():
            rc_update_file.write('[%s]\n' % key)
            rc_update_file.write(getattr(self, key))
            rc_update_file.write('\n\n\n')
            
        rc_update_file.close()
Ejemplo n.º 27
0
    def execute():
        """
        Command line controller.
        Manages program flow from given command line arguments
        """
        # Identify method entry
        debug_print(get_current_method_signature())
        
        parser = argparse.ArgumentParser(prog='',
            usage='\033[01mwatson [OPTION]...',
            description="""
                Running watson with no arguments will parse with settings in
                RC file If no RC file exists, default RC file will be created
                """,
            epilog="""
                Any number of files, tags, dirs, and ignores can be listed after flag
                Ignored files should be space separated
                To use *.filetype identifier, encapsulate in "" to avoid shell substitutions

                Report bugs to: [email protected]
                watson home page: <http://goosecode.com/projects/watson>
                [goosecode] labs | 2012-2013\033[00m
                """)

        parser.add_argument('-c', '--context-depth', dest='context_depth',
            help='number of lines of context to provide with posted issue')
        parser.add_argument('-d', '--dirs', dest='dirs',
            help='list of directories to search in')
        parser.add_argument('-f', '--files', dest='files',
            help='list of files to search in')
        parser.add_argument('-i', '--ignore', dest='ignores',
            help='list of files, directories, or types to ignore')
        parser.add_argument('-p', '--parse-depth', dest='parse_depth',
            help='depth to recursively parse directories')
        parser.add_argument('-r', '--remote', dest='remote',
            help='list / create tokens for Bitbucket/Github')
        parser.add_argument('-s', '--show', dest='show',
            help='whether to show [all, clean, dirty] files')
        parser.add_argument('-t', '--tags', dest='tags',
            help='list of tags to search for')
        parser.add_argument('-u', '--update', dest='update', action='store_const',
            const=True, help='update remote repos with current issues')
        parser.add_argument('-v', '--version', dest='version', action='store_const',
            const=True, help='print watson version and info')        

        args = parser.parse_args()
        
        # If we get the version flag, ignore all other flags. Just display the 
        # version information and exit.
        if args.version:
            return Command.version()

        from watson.config import Config
        Command.config = Config()

        if args.context_depth:
            debug_print('Found -c/--context-depth argument')
            set_context(args.context_depth)

        if args.dirs:
            debug_print('Found -d/--dirs argument')
            set_dirs(args.dirs)

        if args.files:
            debug_print('Found -f/--files argument')
            set_files(args.files)

        if args.ignores:
            debug_print('Found -i/--ignore argument')
            set_ignores(aargs.ignores)

        if args.parse_depth:
            debug_print('Found -p/--parse-depth argument')
            set_parse_depth(args.parse_depth)

        if args.remote:
            debug_print('Found -r/--remote argument')
            Command.config.check_conf()
            Command.config.read_conf()
            setup_remote(args.remote)

            sys.exit(0)

        if args.show:
            debug_print('Found -s/--show argument')
            set_show_type(args.show)
        
        if args.tags:
            debug_print('Found -t/--tags argument')
            set_tags(args.tags)

        if args.update:
            debug_print('Found -u/--update argument')
            Command.config.remote_valid = True

        debug_print("Running watson...")

        Command.config.run()
Ejemplo n.º 28
0
 def set_context(args):
     """
     Set context_depth parameter in config
     """
     # Identify method entry
     debug_print(get_current_method_signature())
Ejemplo n.º 29
0
    def execute():
        """
        Command line controller.
        Manages program flow from given command line arguments
        """
        # Identify method entry
        debug_print(get_current_method_signature())

        parser = argparse.ArgumentParser(prog='',
                                         usage='\033[01mwatson [OPTION]...',
                                         description="""
                Running watson with no arguments will parse with settings in
                RC file If no RC file exists, default RC file will be created
                """,
                                         epilog="""
                Any number of files, tags, dirs, and ignores can be listed after flag
                Ignored files should be space separated
                To use *.filetype identifier, encapsulate in "" to avoid shell substitutions

                Report bugs to: [email protected]
                watson home page: <http://goosecode.com/projects/watson>
                [goosecode] labs | 2012-2013\033[00m
                """)

        parser.add_argument(
            '-c',
            '--context-depth',
            dest='context_depth',
            help='number of lines of context to provide with posted issue')
        parser.add_argument('-d',
                            '--dirs',
                            dest='dirs',
                            help='list of directories to search in')
        parser.add_argument('-f',
                            '--files',
                            dest='files',
                            help='list of files to search in')
        parser.add_argument(
            '-i',
            '--ignore',
            dest='ignores',
            help='list of files, directories, or types to ignore')
        parser.add_argument('-p',
                            '--parse-depth',
                            dest='parse_depth',
                            help='depth to recursively parse directories')
        parser.add_argument('-r',
                            '--remote',
                            dest='remote',
                            help='list / create tokens for Bitbucket/Github')
        parser.add_argument('-s',
                            '--show',
                            dest='show',
                            help='whether to show [all, clean, dirty] files')
        parser.add_argument('-t',
                            '--tags',
                            dest='tags',
                            help='list of tags to search for')
        parser.add_argument('-u',
                            '--update',
                            dest='update',
                            action='store_const',
                            const=True,
                            help='update remote repos with current issues')
        parser.add_argument('-v',
                            '--version',
                            dest='version',
                            action='store_const',
                            const=True,
                            help='print watson version and info')

        args = parser.parse_args()

        # If we get the version flag, ignore all other flags. Just display the
        # version information and exit.
        if args.version:
            return Command.version()

        from watson.config import Config
        Command.config = Config()

        if args.context_depth:
            debug_print('Found -c/--context-depth argument')
            set_context(args.context_depth)

        if args.dirs:
            debug_print('Found -d/--dirs argument')
            set_dirs(args.dirs)

        if args.files:
            debug_print('Found -f/--files argument')
            set_files(args.files)

        if args.ignores:
            debug_print('Found -i/--ignore argument')
            set_ignores(aargs.ignores)

        if args.parse_depth:
            debug_print('Found -p/--parse-depth argument')
            set_parse_depth(args.parse_depth)

        if args.remote:
            debug_print('Found -r/--remote argument')
            Command.config.check_conf()
            Command.config.read_conf()
            setup_remote(args.remote)

            sys.exit(0)

        if args.show:
            debug_print('Found -s/--show argument')
            set_show_type(args.show)

        if args.tags:
            debug_print('Found -t/--tags argument')
            set_tags(args.tags)

        if args.update:
            debug_print('Found -u/--update argument')
            Command.config.remote_valid = True

        debug_print("Running watson...")

        Command.config.run()