Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Solving many bugs when using artisan #28

Open
wants to merge 2 commits into from

2 participants

@bastiaan89

Previously, many artisan commands didn't work well (try routes, list, or migrate:make), due to incorrect use of the Popen class. These have been fixed. Changes of #25 are included in this pull request as well.

Output from artisan commands is now always shown in a panel, and no distinction between successful execution or failure is made; in either case, the response from artisan is displayed in the panel.

@gnarula
Owner

Hey! Thanks for the pull request. I got my macbook back working today so I can continue with the development of the plugin now. I regret for the inactivity during the last few weeks. Reviewing this ASAP.

EDIT: is the commit checked against Windows? I recall users having issues with it. I'll take a while to get working on a Win environment.

Thanks once again

Gaurav

@bastiaan89

Uh, actually it's only been checked against Windows.

@bastiaan89 bastiaan89 commented on the diff
generate.py
((6 lines not shown))
self.proc_status(proc)
except IOError:
sublime.status_message('IOError - command aborted')
def proc_status(self, proc):
- if proc.poll() is None:
- sublime.set_timeout(lambda: self.proc_status(proc), 200)

This was causing a deadlock if there was a sufficient amount of console output. See also http://docs.python.org/2/library/subprocess.html#subprocess.Popen.wait

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@bastiaan89 bastiaan89 commented on the diff
generate.py
@@ -79,13 +79,13 @@ def run(self, *args, **kwargs):
def call_artisan(self, command):
try:
self.PROJECT_PATH = self.window.folders()[0]
- self.args = '%s %s %s' % (self.php_path, os.path.join(self.PROJECT_PATH, 'artisan'), command)
+ self.args = [self.php_path, os.path.join(self.PROJECT_PATH, 'artisan')] + command.split(' ')

Popen arguments should be passed in as list rather than string:

If args is a string, the interpretation is platform-dependent and described below. See the shell and executable arguments for additional differences from the default behavior. Unless otherwise stated, it is recommended to pass args as a sequence.

@gnarula Owner
gnarula added a note

I had it as a list before but ran into some issues with the slashes iirc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@bastiaan89

Well to be honest currently it's not that smooth either, ST freezes completely while executing the commands, which can be really noticeable when doing things which take a bit longer, such as migrations. It would be better to execute them in another thread, although some refactoring will probably be needed for that. See also this one: https://github.com/francodacosta/composer-sublime. In there, the output is just printed real time, while not blocking the entire program. I'm still very much a newbie at ST plugins and Python for that matter, I guess.

@gnarula
Owner

After applying this patch or even in the last commit? Earlier sublime.set_timeout() was being used to prevent the plugin from blocking the main thread and it worked well iirc. Yes, we'll have to refactor some code undoubtedly to implement threading.

@bastiaan89
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jun 17, 2013
  1. @bastiaan89

    Fixed bugs with artisan not working entirely, deadlocks and commands …

    bastiaan89 authored
    …with arguments, added scaffold command
  2. @bastiaan89

    reverted the migration file opening change, this was not the plugin's…

    bastiaan89 authored
    … fault, prevent opening of files for scaffold
This page is out of date. Refresh to see the latest.
Showing with 24 additions and 29 deletions.
  1. +24 −29 generate.py
View
53 generate.py
@@ -25,7 +25,7 @@ def run(self, *args, **kwargs):
self.args = [self.php_path, os.path.join(self.PROJECT_PATH, 'artisan'), 'generate:%s' % self.command]
if os.path.isfile("%s" % os.path.join(self.PROJECT_PATH, 'artisan')):
- if self.command in ['model', 'seed', 'test', 'view', 'migration', 'resource']:
+ if self.command in ['model', 'seed', 'test', 'view', 'migration', 'resource', 'scaffold']:
# call function to do the work
self.window.show_input_panel(self.fill_in, '', self.call_artisan, None, None)
else:
@@ -48,23 +48,23 @@ def call_artisan(self, value=''):
if os.name != 'posix':
self.args = subprocess.list2cmdline(self.args)
try:
- proc = subprocess.Popen(self.args, cwd=self.PROJECT_PATH, shell=False, stdout=subprocess.PIPE)
+ proc = subprocess.Popen(self.args, cwd=self.PROJECT_PATH, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
self.proc_status(proc)
except IOError:
sublime.status_message('IOError - command aborted')
def proc_status(self, proc):
- if proc.poll() is None:
- sublime.set_timeout(lambda: self.proc_status(proc), 200)

This was causing a deadlock if there was a sufficient amount of console output. See also http://docs.python.org/2/library/subprocess.html#subprocess.Popen.wait

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ output = ''
+ while proc.poll() is None:
+ output += proc.communicate()[0]
+
+ match = re.search(r'app/\w+/.*[.]php', output)
+ if match:
+ if not self.command == 'resource' and not self.command == 'scaffold':
+ self.window.open_file('%s/%s' % (self.PROJECT_PATH, match.group(0)))
+ sublime.status_message("%s generated successfully!" % self.command)
else:
- output = proc.communicate()[0].decode('utf-8')
- match = re.search(r'/app/\w+/.*[.]php', output)
- if match:
- if not self.command == 'resource':
- self.window.open_file('%s%s' % (self.PROJECT_PATH, match.group(0)))
- sublime.status_message("%s generated successfully!" % self.command)
- else:
- sublime.status_message("Oh snap! generate:%s failed - %s" % (self.command, output))
+ sublime.status_message("Oh snap! generate:%s failed - %s" % (self.command, output))
class ArtisanCommand(sublime_plugin.WindowCommand):
def __init__(self, *args, **kwargs):
@@ -79,13 +79,13 @@ def run(self, *args, **kwargs):
def call_artisan(self, command):
try:
self.PROJECT_PATH = self.window.folders()[0]
- self.args = '%s %s %s' % (self.php_path, os.path.join(self.PROJECT_PATH, 'artisan'), command)
+ self.args = [self.php_path, os.path.join(self.PROJECT_PATH, 'artisan')] + command.split(' ')

Popen arguments should be passed in as list rather than string:

If args is a string, the interpretation is platform-dependent and described below. See the shell and executable arguments for additional differences from the default behavior. Unless otherwise stated, it is recommended to pass args as a sequence.

@gnarula Owner
gnarula added a note

I had it as a list before but ran into some issues with the slashes iirc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
if os.name == 'posix':
self.args = shlex.split(str(self.args))
if command:
try:
- proc = subprocess.Popen(self.args, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ proc = subprocess.Popen(self.args, cwd=self.PROJECT_PATH, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
self.proc_status(proc, command)
except IOError:
sublime.status_message('IOError - command aborted')
@@ -95,21 +95,16 @@ def call_artisan(self, command):
sublime.status_message('Please open a Laravel Project')
def proc_status(self, proc, command):
- if proc.poll() is None:
- sublime.set_timeout(lambda: self.proc_status(proc, command), 200)
- else:
- result = [x.decode('utf-8') for x in proc.communicate()]
- panel_name = 'artisan_output'
- panel = self.window.get_output_panel(panel_name)
- if not result[1]:
- if command == 'routes':
- panel.run_command('artisan_output', {'insert': result[0]})
- self.window.run_command('show_panel', {'panel': 'output.' + panel_name})
- sublime.status_message('artisan %s executed successfully' % command)
- else:
- panel.run_command('artisan_output', {'insert': result[1]})
- self.window.run_command('show_panel', {'panel': 'output.' + panel_name})
- sublime.status_message('artisan %s failed' % command)
+ output = ''
+ while proc.poll() is None:
+ output += proc.communicate()[0]
+
+ panel_name = 'artisan_output'
+ panel = self.window.get_output_panel(panel_name)
+
+ panel.run_command('artisan_output', {'insert': output})
+ self.window.run_command('show_panel', {'panel': 'output.' + panel_name})
+ sublime.status_message('executed artisan %s' % command)
class ArtisanOutputCommand(sublime_plugin.TextCommand):
def run(self, edit, insert):
Something went wrong with that request. Please try again.