| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257 |
- <?php
- $confFile = __DIR__ . '/gitsync.ini';
- $argk = '';
- foreach ($argv as $k => $v) {
- if ($k == 0) {
- continue;
- }
- switch (strtolower($v)) {
- case '-?':
- case '--help':
- case '-h':
- help();
- case '--conf':
- $argk = 'confFile';
- break;
- default:
- $confs[$argk] = $v;
- }
- }
- if (!empty($confs['confFile'])) {
- $confFile = $confs['confFile'];
- } elseif (!file_exists($confFile)) {
- $confFile = 'gitsync.ini';
- if (!file_exists($confFile)) {
- help();
- }
- }
- $confs = parse_ini_file($confFile, true);
- if (empty($confs['sync']['toPath']) || !file_exists($confs['sync']['toPath']) || !is_dir($confs['sync']['toPath'])) {
- gexit('sync.toPath not found');
- }
- $tmpPath = __DIR__;
- if (!is_writable($tmpPath)) {
- gexit('system path not writable');
- }
- if (!empty($confs['git']['path'])) {
- if (!file_exists($confs['git']['path']) || !is_dir($confs['git']['path'])) {
- gexit('git.path not found');
- }
- $dotGitPath = $confs['git']['path'] . '/.git';
- if (!file_exists($dotGitPath) || !is_dir($dotGitPath)) {
- gexit('git.path: ".git" not found');
- }
- $gitConfig = $dotGitPath . '/config';
- if (!file_exists($gitConfig)) {
- gexit('git.path: ".git/config" not found');
- }
- $gitConfs = parse_ini_file($gitConfig, true);
- if (empty($gitConfs['remote origin']['url'])) {
- gexit('git.path: git url not found in ".git/config"');
- }
- $gitUrl = $gitConfs['remote origin']['url'];
- } elseif (!empty($confs['git']['url'])) {
- $gitUrl = $confs['git']['url'];
- } else {
- gexit('git url not found');
- }
- if (!empty($confs['git']['user']) && !empty($confs['git']['password'])) {
- $e = parse_url($gitUrl);
- $gitUrl = $e['scheme'] . '://' . rawurlencode($confs['git']['user']) . ':' . rawurlencode($confs['git']['password']) . '@' . $e['host'] . $e['path'];
- }
- if (!function_exists('exec')) {
- gexit('exec() function not found');
- }
- $branch = !empty($confs['git']['branch']) ? $confs['git']['branch'] : 'master';
- $tmpPath = $tmpPath . '/gitsync/' . md5($gitUrl . '.' . $branch);
- if (!is_dir($tmpPath)) {
- @mkdir($tmpPath, 0777, true);
- if (!file_exists($tmpPath)) {
- gexit('system temp path not found');
- }
- if (!is_writable($tmpPath)) {
- gexit('system temp path not writable');
- }
- $output = $ret = null;
- $cmd = 'git clone -b ' . $branch . ' ' . $gitUrl . ' ' . $tmpPath;
- exec($cmd, $output, $ret) . "\n";
- if ($ret) {
- gexit('git failed: ' . print_r($output, 1) . ' ' . $ret);
- }
- } else {
- chdir($tmpPath);
- $cmd = 'git fetch --all';
- $output = $ret = null;
- exec($cmd, $output, $ret);
- echo implode("\n", $output) . "\n";
- if ($ret) {
- gexit('git failed: ' . print_r($output, 1) . ' ' . $ret);
- }
- $output = $ret = null;
- $cmd = 'git reset --hard origin/' . $branch;
- exec($cmd, $output, $ret);
- echo implode("\n", $output) . "\n";
- if ($ret) {
- gexit('git failed: ' . print_r($output, 1) . ' ' . $ret);
- }
- $output = $ret = null;
- $cmd = 'git pull';
- exec($cmd, $output, $ret);
- echo implode("\n", $output) . "\n";
- if ($ret) {
- gexit('git failed: ' . print_r($output, 1) . ' ' . $ret);
- }
- }
- $syncFromPath = $tmpPath . (!empty($confs['sync']['fromPath']) ? '/' . $confs['sync']['fromPath'] : '');
- $syncToPath = $confs['sync']['toPath'];
- echo $syncFromPath . ' > ' . $syncToPath . "\n";
- echo "...\n";
- $_ENV['_md5data_root_'] = $syncFromPath;
- $_ENV['_md5data_'] = [];
- $_ENV['_skipdata_'] = $confs['sync']['skipFiles'] ?? [];
- fetchFiles($syncFromPath);
- copyFiles($syncToPath);
- if (!empty($confs['sync']['clearPaths'])) {
- $_ENV['_todata_root_'] = $confs['sync']['toPath'];
- foreach ($confs['sync']['clearPaths'] as $path) {
- if (substr($path, 0, 1) == ':') {
- $path = substr($path, 1);
- $recursion = false;
- } else {
- $recursion = true;
- }
- $path == '/' && $path = '';
- clearFiles($confs['sync']['toPath'] . $path, $recursion);
- }
- }
- gexit('Done');
- function help() {
- echo <<<Help
- Git 文件同步工具 1.0
- ====================
- 用法: php gitsync.php [-?/--help/-h] [--conf <file>]
- 选项:
- -?/--help/-h 帮助
- -conf <file> 配置文件。默认文件名为 gitsync.ini,可放置在当前目录或者脚本所在目录
- gitsync.ini 说明
- --------------------
- [git]
- path = "path"
- url = "https://gitUrl"
- user = "user"
- password = "password"
- branch = "branch1"
- [sync]
- fromPath = "path1"
- toPath = "path2"
- skipFiles[] = "/file1"
- clearPaths[] = "/path1"
- --------------------
- git.path (可选)git 仓库的根目录,必须是包含 .git 文件夹的目录
- git.url (可选)git 仓库的地址,如果填写了 git.path 可不填写此参数
- git.user (可选)git 仓库的用户名,如果 git.path 或者 git.url 包含了账号信息可不填写此参数
- git.password (可选)git 仓库的密码,填写了 git.user 则必须填写此参数
- git.branch (可选)git 仓库的分支,默认为 master
- sync.fromPath (可选)如果从 git 仓库根目录开始同步则可不填写此参数
- sync.toPath 同步的目标文件夹,绝对路径
- sync.skipFiles (可选)同步时跳过的文件,"/" 开头
- sync.clearPaths (可选)清理文件夹中的额外文件夹,"/" 开头,不递归查找以 ":" 开头,如:":/" 为仅清理根文件夹
- Help;
- gexit(0);
- }
- function gexit($code = '') {
- echo $code;
- echo "\n\n";
- exit;
- }
- function fetchFiles($path) {
- foreach (glob($path . '/*') as $file) {
- if (is_dir($file)) {
- fetchFiles($file);
- continue;
- }
- $_ENV['_md5data_'][str_replace($_ENV['_md5data_root_'], '', $file)] = md5_file($file);
- }
- }
- function copyFiles($path) {
- foreach ($_ENV['_md5data_'] as $k => $md5) {
- if (!empty($_ENV['_skipdata_']) && in_array($k, $_ENV['_skipdata_'])) {
- continue;
- }
- $file = $_ENV['_md5data_root_'] . $k;
- $toFile = $path . $k;
- if (!file_exists($toFile)) {
- @mkdir(dirname($toFile), 0777, true);
- $_dir = dirname($toFile);
- if (!is_dir($_dir) || !is_writable($_dir)) {
- gexit('copy file failed, dir not writable: ' . $toFile);
- }
- copy($file, $toFile);
- } else {
- $toMd5 = md5_file($toFile);
- if ($md5 != $toMd5) {
- copy($file, $toFile);
- }
- }
- $toMd5 = md5_file($toFile);
- if ($md5 != $toMd5) {
- unlink($toFile);
- copy($file, $toFile);
- $toMd5 = md5_file($toFile);
- }
- if ($md5 != $toMd5) {
- $toFileBackup = $toFile . '._bak_';
- @unlink($toFileBackup);
- rename($toFile, $toFileBackup);
- if (!file_exists($toFileBackup)) {
- gexit('copy file failed, file not writable: ' . $toFileBackup);
- }
- copy($file, $toFile);
- if (file_exists($toFile)) {
- @unlink($toFileBackup);
- }
- $toMd5 = md5_file($toFile);
- }
- if ($md5 != $toMd5) {
- gexit('copy file failed, md5 not match: ' . $toFile);
- }
- }
- }
- function clearFiles($path, $recursion = true) {
- foreach (glob($path . '/*') as $file) {
- if (is_dir($file)) {
- $recursion && clearFiles($file);
- continue;
- }
- $key = str_replace($_ENV['_todata_root_'], '', $file);
- if (empty($_ENV['_md5data_'][$key])) {
- echo 'delete: ' . $file . "\n";
- unlink($file);
- }
- }
- }
|