Skip to content

Commit

Permalink
拆分删除 derived_data 的逻辑
Browse files Browse the repository at this point in the history
为提示增加更多信息
  • Loading branch information
zlrs committed Sep 1, 2020
1 parent 66b1345 commit a115247
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 73 deletions.
100 changes: 100 additions & 0 deletions derived_data_clearner.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import sys
import os
import shutil
from logger import printInfo, printExecute, printError
import plistlib
from typing import List, Set, Dict, Tuple, Optional


def parsePlist(plist_file_path) -> dict:
obj = {}
if os.path.exists(plist_file_path):
try:
with open(plist_file_path, 'rb') as f:
obj = plistlib.load(f)
except Exception as e:
printError(e)

return obj


def workspacePathFromPlist(plist_file_path) -> str:
workspacePath = ''
try:
obj: dict = parsePlist(plist_file_path)
workspacePath = obj.get('WorkspacePath')
except Exception as e:
printError(e)

return workspacePath


def removeProjectDerivedData(proj_file_path, rmAll=False, rmBuild=False, rmIndex=False):
"""Remove directories from the project's derived data.
Specifically the `Index` directory, `Build` directory, or all directories.
"""
def removeDirIfExist(rmDirPath, ignore_errors=False):
if os.path.exists(rmDirPath) and os.path.isdir(rmDirPath):
printInfo('Removing directory: ' + rmDirPath)
shutil.rmtree(rmDirPath, ignore_errors=ignore_errors)
return rmDirPath
return None

def handleRemoveSingleProject(singleProjPath, rmAll=False, rmBuild=False, rmIndex=False):
proj_index_dir = os.path.join(singleProjPath, 'Index')
proj_build_dir = os.path.join(singleProjPath, 'Build')
if rmAll:
removeDirIfExist(singleProjPath)
else:
if rmIndex:
removeDirIfExist(proj_index_dir)
if rmBuild:
removeDirIfExist(proj_build_dir)

def chooseFromPrompt(candidates: List[Tuple]) -> List[Tuple]:
index_offset = 1
lines = ['Choose the project to operate on:']
for i, candidate in enumerate(candidates, start=index_offset):
_line = f'{i}. {candidate}'
lines.append(_line)
lines.append('ALL: all above.\n')

prompt = '\n'.join(lines)
cmd = input(prompt)
if cmd.isnumeric():
idx = int(cmd) - index_offset
if 0 <= idx < len(candidates):
return [candidates[idx]]
elif cmd == 'ALL':
return candidates
return []

derived_data_path = os.path.expanduser('~/Library/Developer/Xcode/DerivedData/')

proj_name = os.path.splitext(os.path.basename(proj_file_path))[0]
if proj_name is None or len(proj_name) < 1:
return 1

# Scan XCode derivedData folder to find out the candidate project(s) that we may need to
# do remove operation on.
candidates: List[Tuple] = []
for proj_dir in os.listdir(derived_data_path):
if proj_dir.startswith(proj_name):
proj_derived_data_dir = os.path.join(derived_data_path, proj_dir)
workspacePath = workspacePathFromPlist(os.path.join(proj_derived_data_dir, 'info.plist'))
candidates.append((proj_derived_data_dir, workspacePath))

# Decide the part of project(s) in `candidates` to we really to do remove operation
# chosen_ones: List[Tuple] = []
# if len(candidates) == 1:
# chosen_ones = [candidates[0]]
# elif len(candidates) > 1:
chosen_ones: List[Tuple] = chooseFromPrompt(candidates)

# Handle the removing all chosen projects
for chosen_candidate in chosen_ones:
chosen_derived_data_path = chosen_candidate[0]
chosen_proj_source_path = chosen_candidate[1]
handleRemoveSingleProject(chosen_derived_data_path, rmAll=rmAll, rmBuild=rmBuild, rmIndex=rmIndex)

return 0
6 changes: 3 additions & 3 deletions version_check.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import json
from logger import printInfo, printExecute, printError

VERSION = '1.2.2'
VERSION = '1.2.3'
VERSION_CHECK_TIMES = 7

# ANSI colors
Expand Down Expand Up @@ -35,8 +35,8 @@ def __lt__(self, other):


def getLatestVersion():
URL = 'https://api.github.com/repos/zlrs/xcode-opener/releases?accept=application/vnd.github.v3+json'
res = requests.get(URL)
releases_API_URL = 'https://api.github.com/repos/zlrs/xcode-opener/releases?accept=application/vnd.github.v3+json'
res = requests.get(releases_API_URL)
if not res.ok:
return '', f"error: status {res.status_code}" # May be 403: exceeded API rate limit for current IP.

Expand Down
78 changes: 8 additions & 70 deletions xc
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
#!/usr/bin/python3
import sys
import os
import shutil
import click
import version_check
from logger import printInfo, printExecute, printError
from derived_data_clearner import removeProjectDerivedData


def getXCodeProjectOrWorkspaceFilePath(inputPath) -> str:
Expand Down Expand Up @@ -65,72 +65,10 @@ def openInXcode(inputPath):
printInfo('No .xcodeproj / .xcworkspace file is found. ')


def removeProjectDerivedData(inputPath, rmAll=False, rmBuild=False, rmIndex=False):
"""Remove directories from the project's derived data.
Specifically the `Index` directory, `Build` directory, or all directories.
"""
def removeDirIfExist(rmDirPath, ignore_errors=False):
if os.path.exists(rmDirPath) and os.path.isdir(rmDirPath):
printInfo('Removing directory: ' + rmDirPath)
shutil.rmtree(rmDirPath, ignore_errors=ignore_errors)
return rmDirPath
return None

def handleRemoveSingleProject(singleProjPath, rmAll=False, rmBuild=False, rmIndex=False):
proj_index_dir = os.path.join(singleProjPath, 'Index')
proj_build_dir = os.path.join(singleProjPath, 'Build')
if rmAll:
removeDirIfExist(singleProjPath)
else:
if rmIndex:
removeDirIfExist(proj_index_dir)
if rmBuild:
removeDirIfExist(proj_build_dir)

def chooseFromPrompt(candidates: list) -> list:
index_offset = 1
lines = ['Choose the project to operate on:']
for i, candidate in enumerate(candidates, start=index_offset):
_line = f'{i}. {candidate}'
lines.append(_line)
lines.append('ALL: all above.\n')

prompt = '\n'.join(lines)
cmd = input(prompt)
if cmd.isnumeric():
idx = int(cmd) - index_offset
if 0 <= idx < len(candidates):
return [candidates[idx]]
elif cmd == 'ALL':
return candidates
return []

derived_data_path = os.path.expanduser('~/Library/Developer/Xcode/DerivedData/')

def removeDerivedData(inputPath, rmAll=False, rmBuild=False, rmIndex=False):
""" Handle `--rm-` options """
proj_file_path = getXCodeProjectOrWorkspaceFilePath(inputPath)
proj_name = os.path.splitext(os.path.basename(proj_file_path))[0]
if proj_name is None or len(proj_name) < 1:
return 1

# Scan XCode derivedData folder to find out the candidate project(s) that we may need to
# do remove operation on.
candidates = []
for proj_dir in os.listdir(derived_data_path):
if proj_dir.startswith(proj_name):
candidates.append(os.path.join(derived_data_path, proj_dir))

# Decide the part of project(s) in `candidates` to we really to do remove operation
chosen_ones = []
if len(candidates) == 1:
chosen_ones = list(candidates[0])
elif len(candidates) > 1:
chosen_ones = chooseFromPrompt(candidates)

# Handle the removing all chosen projects
for chosen_candidate in chosen_ones:
handleRemoveSingleProject(chosen_candidate, rmAll=rmAll, rmBuild=rmBuild, rmIndex=rmIndex)

return 0
removeProjectDerivedData(proj_file_path, rmAll=rmAll, rmBuild=rmBuild, rmIndex=rmIndex)


# developer note: click option name must be lower case
Expand Down Expand Up @@ -158,14 +96,14 @@ def xc(path, rm_all, rm_build, rm_index, version):
print(version_check.VERSION)
exit(0)

abs_path = os.path.expanduser(path)
abs_input_path = os.path.expanduser(path)

exit_val = 0
if os.path.exists(abs_path):
if os.path.exists(abs_input_path):
if rm_all or rm_build or rm_index:
removeProjectDerivedData(abs_path, rmAll=rm_all, rmBuild=rm_build, rmIndex=rm_index)
removeDerivedData(abs_input_path, rmAll=rm_all, rmBuild=rm_build, rmIndex=rm_index)
else:
openInXcode(abs_path)
openInXcode(abs_input_path)
else:
click.echo('input path not exist.')
exit_val = 1
Expand Down

0 comments on commit a115247

Please sign in to comment.