Completed
Pull Request — master (#519)
by Michael
04:23
created

FetchJob::perform()   C

Complexity

Conditions 12
Paths 130

Size

Total Lines 54
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 54
rs 6.0988
cc 12
eloc 33
nc 130
nop 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
class FetchJob extends DeploynautJob {
4
5
	public $args;
6
7
	/**
8
	 * @var DNProject
9
	 */
10
	protected $project;
11
12
	/**
13
	 * @var DeploynautLogFile
14
	 */
15
	protected $log;
16
17
	/**
18
	 * @var string
19
	 */
20
	protected $user;
21
22
	/**
23
	 * @global array $databaseConfig
24
	 */
25
	public function setUp() {
26
		global $databaseConfig;
27
		DB::connect($databaseConfig);
28
29
		$this->updateStatus('Started');
30
		chdir(BASE_PATH);
31
	}
32
33
	public function tearDown() {
34
		$this->updateStatus('Finished');
35
		chdir(BASE_PATH);
36
	}
37
38
	public function onFailure(Exception $exception) {
39
		$this->updateStatus('Failed');
40
	}
41
42
	public function perform() {
43
		set_time_limit(0);
44
45
		if(!empty($this->args['logfile'])) {
46
			$this->log = new DeploynautLogFile($this->args['logfile']);
47
		}
48
49
		$this->project = DNProject::get()->byId($this->args['projectID']);
50
		if(!($this->project && $this->project->exists())) {
51
			throw new RuntimeException(sprintf('Project ID %s not found', $this->args['projectID']));
52
		}
53
54
		$this->user = DNData::inst()->getGitUser() ?: null;
55
56
		// Disallow concurrent git fetches on the same project.
57
		// Only consider fetches started in the last 30 minutes (older jobs probably got stuck)
58
		try {
59
			if(!empty($this->args['fetchID'])) {
60
				$runningFetches = DNGitFetch::get()
61
					->filter(array(
62
						'ProjectID' => $this->project->ID,
63
						'Status' => array('Queued', 'Started'),
64
						'Created:GreaterThan' => strtotime('-30 minutes')
65
					))
66
					->exclude('ID', $this->args['fetchID']);
67
68
				if($runningFetches->count()) {
69
					$runningFetch = $runningFetches->first();
70
					$message = sprintf(
71
						'Another fetch is in progress (started at %s by %s)',
72
						$runningFetch->dbObject('Created')->Nice(),
73
						$runningFetch->Deployer()->Title
74
					);
75
					if($this->log) {
76
						$this->log->write($message);
77
					}
78
					throw new RuntimeException($message);
79
				}
80
			}
81
82
			// Decide whether we need to just update what we already have
83
			// or initiate a clone if no local repo exists.
84
			if($this->project->repoExists() && empty($this->args['forceClone'])) {
0 ignored issues
show
Bug introduced by
The method repoExists() does not exist on DataObject. Did you maybe mean exists()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
85
				$this->fetchRepo();
86
			} else {
87
				$this->cloneRepo();
88
			}
89
		} catch(Exception $e) {
90
			if($this->log) {
91
				$this->log->write($e->getMessage());
92
			}
93
			throw $e;
94
		}
95
	}
96
97
	protected function fetchRepo() {
98
		$this->runCommand(
99
			'git fetch -p origin +refs/heads/*:refs/heads/* --tags',
100
			$this->project->getLocalCVSPath()
101
		);
102
	}
103
104
	protected function cloneRepo() {
105
		if(file_exists($this->project->getLocalCVSPath())) {
106
			$this->runCommand(sprintf(
107
				'rm -rf %s',
108
				escapeshellarg($this->project->getLocalCVSPath())
109
			));
110
		}
111
112
		$this->runCommand(sprintf(
113
			'git clone --bare -q %s %s',
114
			escapeshellarg($this->project->CVSPath),
115
			escapeshellarg($this->project->getLocalCVSPath())
116
		));
117
	}
118
119
	/**
120
	 * Run a shell command.
121
	 *
122
	 * @param string $command The command to run
123
	 * @param string|null $workingDir The working dir to run command in
124
	 * @throws RuntimeException
125
	 */
126
	protected function runCommand($command, $workingDir = null) {
127
		if(!empty($this->user)) {
128
			$command = sprintf('sudo -u %s %s', $this->user, $command);
129
		}
130
		if($this->log) {
131
			$this->log->write(sprintf('Running command: %s', $command));
132
		}
133
		$process = new \Symfony\Component\Process\Process($command, $workingDir);
134
		$process->setEnv($this->project->getProcessEnv());
135
		$process->setTimeout(1800);
136
		$process->run();
137
		if(!$process->isSuccessful()) {
138
			throw new RuntimeException($process->getErrorOutput());
139
		}
140
	}
141
142
	/**
143
	 * @param string $status
144
	 * @global array $databaseConfig
145
	 */
146
	protected function updateStatus($status) {
147
		global $databaseConfig;
148
		DB::connect($databaseConfig);
149
150
		if(!empty($this->args['fetchID'])) {
151
			$fetch = DNGitFetch::get()->byID($this->args['fetchID']);
152
			if($fetch && $fetch->exists()) {
153
				$fetch->Status = $status;
154
				$fetch->write();
155
			}
156
		}
157
	}
158
159
}
160