Mac电脑上安装多版本的Python

1.安装Homebrew
➜/usr/bin/ruby -e “$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)”

验证是否安装成功

➜ brew -v

2.安装pyenv
首先通过homebrew安装pyenv,之后的所有Python安装和管理通过pyenv进行。

➜ brew install pyenv

验证是否安装成功

➜ pyenv -v

3.查看可以安装的Python版本
➜ pyenv install –list

结果:

Available versions:
2.7
2.7.1
2.7.2

4.安装需要的Python版本
➜ pyenv install 3.5.2

5.查看目前正在使用的Python版本
前面带星号(*)的就是表示当前使用的Python版本(3.4.3)

➜ pyenv versions

6.切换Python版本
如果需要在不同版本的Python间进行切换的话,使用以下命令:

➜ pyenv global 3.3.1

当然,你也可以让版本切换只对当前目录生效

➜ pyenv local 2.7.5

Mac上安装多个版本的Python

简介
利用Mac包管理工具brew安装pyenv,pyenv用来管理所有python版本。如果没有安装brew,先安装一下吧。

安装pyevn
$ brew install pyenv
$ pyenv -v
pyenv 1.2.6

查看所有的python版本(pyenv管理的所有版本)
$ pyenv versions
* system (set by /Users/xxx/.pyenv/version)
* 表示当前正在使用的版本,system表示用的是系统python版本

查看可安装python版本
$ pyenv install –list
Available versions:
2.1.3
2.2.3
2.3.7

选择版本进行安装
$ pyenv install 3.5.5
python-build: use openssl from homebrew
python-build: use readline from homebrew
Downloading Python-3.5.5.tar.xz…
-> https://www.python.org/ftp/python/3.5.5/Python-3.5.5.tar.xz
Installing Python-3.5.5…
python-build: use readline from homebrew
Installed Python-3.5.5 to /Users/xxx/.pyenv/versions/3.5.5

墙内环境,会卡在这里,可以开代理,或者使用国内镜像。
使用国内镜像:

v=3.5.5|wget http://mirrors.sohu.com/python/$v/Python-$v.tar.xz -P ~/.pyenv/cache/;pyenv install $v
查看所有安装的版本
$ pyenv versions
* system (set by /Users/xxx/.pyenv/version)
3.5.5

可以看到多了一个3.5.5版

我在这一步进行安装的时候出现了一个错误如下:

ownloading Python-3.4.1.tgz…-https://yyuu.github.io/pythons/44a3c1ef1c7ca3e4fd25242af80ed72da941203cb4ed1a8c1b724d9078965dd8
Installing Python-3.4.1…

BUILD FAILED (OS X 10.9.5 using python-build 20150124)

Inspect or clean up the working tree at /var/folders/zf/1b6kcyd53hg0crv65j108_7m0000gn/T/python-build.20150127150918.87726
Results logged to /var/folders/zf/1b6kcyd53hg0crv65j108_7m0000gn/T/python-build.20150127150918.87726.log

Last 10 log lines:
File “/private/var/folders/zf/1b6kcyd53hg0crv65j108_7m0000gn/T/python-build.20150127150918.87726/Python-3.4.1/Lib/ensurepip/__main__.py”, line 4, in <module>
ensurepip._main()
File “/private/var/folders/zf/1b6kcyd53hg0crv65j108_7m0000gn/T/python-build.20150127150918.87726/Python-3.4.1/Lib/ensurepip/__init__.py”, line 209, in _main
default_pip=args.default_pip,
File “/private/var/folders/zf/1b6kcyd53hg0crv65j108_7m0000gn/T/python-build.20150127150918.87726/Python-3.4.1/Lib/ensurepip/__init__.py”, line 116, in bootstrap
_run_pip(args + [p[0] for p in _PROJECTS], additional_paths)
File “/private/var/folders/zf/1b6kcyd53hg0crv65j108_7m0000gn/T/python-build.20150127150918.87726/Python-3.4.1/Lib/ensurepip/__init__.py”, line 40, in _run_pip
import pip
zipimport.ZipImportError: can’t decompress data; zlib not available
make: *** [install] Error 1

使用如下命令即可成功

CFLAGS=”-I$(xcrun –show-sdk-path)/usr/include” pyenv install -v 3.4.1

切换版本
$ pyenv global 3.5.5 # 全局切换
$ python -V # 验证一下是否切换成功

此处用也可用local,只对当前目录生效
$ pyenv local 3.5.5 # 当前目录及其目录切换
$ python -V # 验证一下是否切换成功

此处有坑!
用pyenv versions查看,明明已经切换成功,但是用python -V却还是系统版本。原因是pyenv没有加到$PATH环境变量里去,解决办法如下:

export PYENV_ROOT=~/.pyenv
export PATH=$PYENV_ROOT/shims:$PATH

此时,再次查看python -V,已经成功切换到pyenv指定的版本。

可以把上边两句加到~/.bash_profile里去,永久生效。

有时设置了pyenv local版本后,再设置global会发现没有生效,可以尝试:

pyenv local –unset

解除local设置。

要切换回系统版本,用同样命令:

$ pyenv global system

卸载python版本
$ pyenv uninstall 3.5.5

查看pyenv指令列表
$ pyenv commands
–version
commands
completions
exec
global
help
hooks
init
install
local
prefix
realpath.dylib
rehash
root
shell
shims
uninstall
version
version-file
version-file-read
version-file-write
version-name
version-origin
versions
whence
which

在iOS设备中跑Python脚本

在iOS设备中运行python脚本?那不就意味着可以在手机上跑爬虫,可以使用各种牛逼哄哄的python库了吗。

这个标题对我很有吸引力,曾经就有见到过在iOS平台上的python编译器(很多iOS上python的IDE,如Python3IDE),可以执行输入的python语和本地的python文件。

当然我想要的不是像这篇文章说的用python编写一整个iOS程序,而只是在iOS应用中嵌入python文件执行非UI的逻辑,也就是说只需要在项目中嵌入一个python的编译环境。

面对市场上这么多的iOS版python编译器,首先可以确定的是,针对iOS端的python编译库是存在的。我关心的问题是,能否支持python项目化的编译,能否导入丰富的三方库。那就动手一试咯

小目标
七牛的iOS平台SDK有这样一个特点,上传文件的时候需要生成token,但是生成token的逻辑在客户端的SDK中不存在,只能通过调用服务端的SDK才能获得。
于是我们的小目标就诞生了:在iOS端上调用七牛python服务端SDK来生成token给客户端的七牛SDK使用。

iOS的Python解释器
针对iOS、MacOS平台,pybee开源了python支持库Python-Apple-support,这个是老版本的库Python-iOS-support.

准备编译环境
我这次使用的是老库中的Python3.4.2-b5版本,下载下来有两个framework,分别是OpenSSL和Python。将这个两个framework拖入项目中,添加必要的lib库如图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i677eEv4-1571197613226)(http://ojam5z7vg.bkt.clouddn.com/15359053297417.jpg)]

在项目中创建PythonEnvironment.bundle将Python.framework中的Restources文件夹内容复制进去,在初始化Python环境之前将bundle中的文件复制到指定目录作为Home路径

设置Home路径、初始化
设置上面准备home路径,并初始化编译环境。

const char * frameworkPath = [[NSString stringWithFormat:@”%@/Resources”,[self p_pythonFrameworkPath]] UTF8String];
wchar_t *pythonHome = _Py_char2wchar(frameworkPath, NULL);
Py_SetPythonHome(pythonHome);

Py_Initialize();
PyEval_InitThreads();

//在释放的时候调用
Py_Finalize();

执行Python代码、文件
编译环境设置好之后,使用PyRun_SimpleString(python_code)便可以简单执行Python代码

PyRun_SimpleString(“print(‘hello world’)”);
1
便可以输出hello world

执行Python文件
NSString *scriptPath = [[NSBundle mainBundle] pathForResource:@”test” ofType:@”py”];

FILE *mainFile = fopen([scriptPath UTF8String], “r”);

PyRun_SimpleFile(mainFile, (char *)[[scriptPath lastPathComponent] UTF8String]);

上面是执行main bundle中的Python文件方式,这种方式暂时没有找到如何调用文件中的某各类具体方法和传参。

另外一种方式可以做到上面描述的需求,将在下一节中说明

准备七牛Python库
下载好的七牛SDK文件源码解压,在Xcode中创建一个bundle加入项目中,bundle中放七牛SDK的核心文件,如图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3gkKeCdO-1571197613227)(http://ojam5z7vg.bkt.clouddn.com/15359397140219.jpg)]

在需要使用七牛SDK之前,将此bundle中的文件拷贝到Python运行环境的home目录下

编写token生成Python文件
查看七牛的文档了解到生成token需要用到auth.py这个文件中的Auth类, 我们需要想办法创建一个Auth实例并传入需要的参数,再将生成的token导出来。

首先自己创建一个iostoken.py文件,Python的文件名和方法名需要小写,类名需要大写。在iostoken.py中创建TokenForiOS类

import json
from qiniu import Auth

class TokenForiOS(object):

def create_token(jsonParams):
print(str(jsonParams))
values = json.loads(jsonParams)
access_key = values.get(‘access_key’)
secret_key = values.get(‘secret_key’)
#要上传的空间
bucket_name = values.get(‘bucket_name’)
#上传到七牛后保存的文件名
file_name = values.get(‘file_name’)
#构建鉴权对象
q = Auth(access_key, secret_key)
#生成上传 Token,可以指定过期时间等
token = q.upload_token(bucket_name, file_name, 3600)
return token

上面是我使用七牛SDK中的Auth生成token的代码,类名为TokenForiOS方法名为create_token,现在需要找到合适的地方调用。

不过在想要使用TokenForiOS类之前,需要将其加入qiniu模块的初始化__init__.py中:

from .iostoken import TokenForiOS
1
接下来就可以愉快地调用了

Python.framework中有一套宏可以导入Python模块,生成实例,传参调用方法,具体使用例子见下代码块

PyObject *pModule = PyImport_ImportModule([@”qiniu.iostoken” UTF8String]);//导入模块

PyObject *pyClass = PyObject_GetAttrString(pModule, [@”TokenForiOS” UTF8String]);//获取类

PyObject *pyInstance = PyInstanceMethod_New(pyClass); //创建实例

NSMutableDictionary *params = [NSMutableDictionary new];
[params setObject:@”123″ forKey:@”access_key”];
[params setObject:@”456″ forKey:@”secret_key”];
[params setObject:@”jake” forKey:@”bucket_name”];
[params setObject:@”pic” forKey:@”file_name”];

NSError *error = nil;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:params options:NSJSONWritingPrettyPrinted error:&error];
NSString *paramterJsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];

PyObject *result = NULL;
result = PyObject_CallMethod(pyInstance, [@”create_token” UTF8String], “(s)”, [paramterJsonString UTF8String] );

char * resultCString = NULL;
PyArg_Parse(result, “s”, &resultCString); //将python类型的返回值转换为c

NSLog(@”%s”, resultCString);

至此,我的小目标就完成啦。后面还有很多事情可以做,比如跑个爬虫试试,毕竟还没有尝试过网络请求。当然也还有很多坑要踩。

总结
使用过程中有下面几点体会

Python-Apple-support库的缺少文档 其实就是Python的API库
设置Home目录导入模块的过程中踩了很多坑
编译器对Python语法提示并不支持,难以排查写错的地方
framework的体积是在过大,对项目总体积影响大
PS:在查询过程中发现了PyObjc这个项目,能够使用python通过bridge调用OC的方法从而使用Cocoa框架,实现使用python编写Cocoa GUI应用。

PyObjC is a bridge between Python and Objective-C. It allows Python scripts to use and extend existing Objective-C class libraries; most importantly the Cocoa libraries by Apple.

This document describes how to use Objective-C class libraries from Python scripts and how to interpret the documentation of those libraries from the point of view of a Python programmer.

Android后台service保活的一种方式

让App的service在后台长久运行其实是很流氓的做法,但是“刚性”的需求就摆在那里。。。
各种招式尝试了一圈,发现一个目前来看还算靠谱的方法,详情如下。

方案思想
监听手机的锁屏和亮屏事件,在锁屏时启动一个透明的Activity,在亮屏时将Activity销毁掉(该Activity在整个过程中用户无感知)。
本质:使进程的优先级在锁屏期间由4提升为1。

具体实现
1、先定义一个Activity,设置其大小为1像素。

public class KeepAlive_Activity extends Activity
{
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);

//只有左上角的一个点,主要为了使用户无感知
Window window = getWindow();
window.setGravity(Gravity.LEFT | Gravity.TOP);

WindowManager.LayoutParams params = window.getAttributes();
params.x = 0;
params.y = 0;
params.height = 1;
params.width = 1;
window.setAttributes(params);

//通过EventBus来接收消息
EventBus.getDefault().register(this);
}

@Override
protected void onDestroy()
{
super.onDestroy();
EventBus.getDefault().unregister(this);
}

// EventBus ——————————
@Subscribe (threadMode = ThreadMode.MAIN)
public void onMessageEvent(EventMessage msg)
{
int msgCode = msg.msgCode;
switch (msgCode)
{
case Event_Finish_KeepAliveActivity:
KeepAlive_Activity.this.finish();
break;

default:
break;
}
}
}

2、在AndroidManifest中设置属性,排除该Activity在RecentTask中的显示:

<activity android:name=”.KeepAlive_Activity”
android:configChanges=”keyboardHidden|orientation”
android:excludeFromRecents=”true”
android:exported=”false”
android:finishOnTaskLaunch=”false”
android:launchMode=”singleInstance”
android:screenOrientation=”portrait”
android:theme=”@style/AliveActivity_style”/>

3、在styles.xml中设置该Activity为透明:

<style name=”AliveActivity_style”>
<item name=”android:windowBackground”>@android:color/transparent</item>
<item name=”android:windowIsTranslucent”>true</item>
<item name=”android:background”>@null</item>
</style>

4、此Activity的启动与销毁

/* 注册广播,监听手机屏幕事件 */
myReceiver = new MyReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_ON); //亮屏
filter.addAction(Intent.ACTION_SCREEN_OFF); //锁屏、黑屏
this.registerReceiver(myReceiver, filter);

class MyReceiver extends BroadcastReceiver
{
@Override
public void onReceive(Context context, Intent intent)
{
String action = intent.getAction();
if (action.equals(Intent.ACTION_SCREEN_OFF)) //锁屏、黑屏
{
//启动保活Activity
Intent aIntent = new Intent(XX_Activity.this, KeepAlive_Activity.class);
startActivity(aIntent);
}
else if (action.equals(Intent.ACTION_SCREEN_ON)) //亮屏
{
//移除保活Activity
EventBus.getDefault().post(new EventMessage(Event_Finish_KeepAliveActivity, “”));
}
}
}

receiver记得解绑

@Override
protected void onDestroy()
{
super.onDestroy();
EventBus.getDefault().unregister(this);

if (myReceiver != null)
{
this.unregisterReceiver(myReceiver);
myReceiver = null;
}
}

更多
1、方案参考至 http://blog.csdn.net/u011622280/article/details/52311344,略有调整。
原方案是监听的锁屏(ACTION_SCREEN_OFF)和解锁(ACTION_USER_PRESENT)两个事件,略有瑕疵,因为锁屏和解锁并不总是成对出现,比如App内的某处跳转到了打电话,手机靠近耳朵,手机锁屏,电话打完离开耳朵,手机亮屏(但并没有解锁),这时点击挂电话是无效的(因为那个透明的Activity还浮在上面)。
锁屏(ACTION_SCREEN_OFF)和亮屏(ACTION_SCREEN_ON)是成对出现的,监听它们会比较安全。
2、该方案只能增强App后台运行优先级,避免被系统销毁,若用户手动结束或杀掉App,后台service仍然可以被销毁。
3、方案中的消息传递采用了EventBus,也可以采用其它方式。

Android提高String拼接性能分析

String拼接在频繁使用时,不同方法性能差别较大:

package com.example.ss.hello;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

private TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView)findViewById(R.id.hello);
long n = 10000;

long start1 = System.currentTimeMillis();
String s1 = new String(“hello”);
for (long i = 0; i < n; i++)
{
s1 += “拼接–“;
}
long end1 = System.currentTimeMillis();
long time1 = end1 – start1;
tv.setText(“用String+=拼接字符串的时间:” + time1);

long start2 = System.currentTimeMillis();
String s2 = new String(“hello”);
for (long i = 0; i < n; i++)
{
s2 = s2 + “拼接–“;
}
long end2 = System.currentTimeMillis();
long time2 = end2 – start2;
tv.append(“用String=String+拼接字符串的时间” + time2);

long start3 = System.currentTimeMillis();
String s3 = new String(“hello”);
for (long i = 0; i < n; i++)
{
s3 = s3.concat(“拼接–“);
}
long end3 = System.currentTimeMillis();
long time3 = end3 – start3;
tv.append(“用String.concat拼接字符串的时间” + time3);

long start4 = System.currentTimeMillis();
StringBuffer s4 = new StringBuffer(“hello”);
for (long i = 0; i < n; i++)
{
s4.append(“拼接–“);
}
long end4 = System.currentTimeMillis();
long time4 = end4 – start4;
tv.append(“用StringBuffer.append拼接字符串的时间” + time4);

long start5 = System.currentTimeMillis();
StringBuilder s5 = new StringBuilder(“hello”);
for (long i = 0; i < n; i++)
{
s5.append(“拼接–“);
}
long end5 = System.currentTimeMillis();
long time5 = end5 – start5;
tv.append(“用StringBuilder.append拼接字符串的时间” + time5);
}
}
真机运行结果如下

可见使用+= 与使用StringBuilder.append差别达到了指数级。

频繁使用拼接的操作中若使用+=,则有可能造成频繁GC,从而产生丢帧的现象。

Android+Java设置开机启动

Android+Java设置开机启动—开机解锁并直接进入应用

 使用Java在Android环境下开发应用,设置该应用为开机自动运行,使用一个简单的Hello,World!程序进行测试。

1.首先写一个简单的只显示一行文字的代码如下,类SayHello.class:

package com.example.bootstartdemo;

import android.app.Activity;
import android.os.Bundle;
import android.view.*;

public class SayHello extends Activity{
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);

getWindow().setFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD,
WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
setContentView(R.layout.activity_main);
}
}
创建一个只显示一行文字的Activity,并将开机锁定功能关闭
getWindow().setFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD,
WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD)
对应的XML代码如下:

<FrameLayout xmlns:android=”http://schemas.android.com/apk/res/android”
xmlns:tools=”http://schemas.android.com/tools”
android:id=”@+id/container”
android:layout_width=”match_parent”
android:layout_height=”match_parent”
tools:context=”com.example.bootstartdemo.MainActivity”
tools:ignore=”MergeRootFrame” >

<LinearLayout
android:layout_width=”match_parent”
android:layout_height=”match_parent”
android:orientation=”vertical” >

<TextView
android:id=”@+id/textView1″
android:layout_width=”match_parent”
android:layout_height=”wrap_content”
android:layout_weight=”0.70″
android:text=”Hello,Android,this is Shine!” />
</LinearLayout>

</FrameLayout>

2.接收广播消息类 BroadcastReceiver.class
package com.example.bootstartdemo;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

public class BootBroadcastReceiver extends BroadcastReceiver{
static final String ACTION = “android.intent.action.BOOT_COMPLETED”;
@Override
public void onReceive(Context context,Intent intent){
if(intent.getAction().equals(ACTION))
{
Intent sayHelloIntent = new Intent(context,SayHello.class);
sayHelloIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(sayHelloIntent);
}
}
}
该类继承自BroadcastReceiver,并重写方法onReceive。使用Intent判断是否是进行的动作,即开机完成BOOT_COMPLETED,如果是,则下一步关联到SayHello类进行处理,SayHelloIntent将上下文与SayHello类进行绑定,作为无参数的activity跳转。(Intent是一种传参方式。)

3.配置文件:AndroidManifest.xml

<?xml version=”1.0″ encoding=”utf-8″?>
<manifest xmlns:android=”http://schemas.android.com/apk/res/android”
package=”com.example.bootstartdemo”
android:versionCode=”1″
android:versionName=”1.0″ >
<uses-sdk
android:minSdkVersion=”8″
android:targetSdkVersion=”15″ />
<application
android:allowBackup=”true”
android:icon=”@drawable/ic_launcher”
android:label=”@string/app_name”
android:theme=”@style/AppTheme” >
<activity
android:name=”com.example.bootstartdemo.SayHello”
android:label=”@string/app_name” >
<intent-filter>
<action android:name=”android.intent.action.MAIN” />
<category android:name=”android.intent.category.LAUNCHER” />
</intent-filter>
</activity>
<receiver android:name=”.BootBroadcastReceiver” >
<intent-filter>
<action android:name=”android.intent.action.BOOT_COMPLETED” />
</intent-filter>
</receiver>
</application>
<uses-permission android:name=”android.permission.RECEIVE_BOOT_COMPLETED”></uses-permission>
</manifest>
其中

<receiver android:name=”.BootBroadcastReceiver” >
<intent-filter>
<action android:name=”android.intent.action.BOOT_COMPLETED” />
</intent-filter>
</receiver>
表示接受者为BootBroadcastReceiver可接收的动作是BOOT_COMPLETED,根据该配置,在进行该动作时,与该类关联。要配置
android.permission.RECEIVE_BOOT_COMPLETED
权限,否则设置不成功。

本地navicat连接百度云服务器的坑

①要先在百度云控制台给服务器绑定一个 入站 3306端口的安全组
②服务器上边安装的mysql是禁止远程访问的,可以通过下述方法。
改表法。

可能是你的帐号不允许从远程登陆,只能在localhost。这个时候只要在localhost的那台电脑,登入mysql后,更改 “mysql” 数据库里的 “user” 表里的 “host” 项,从”localhost”改称”%”

mysql -u root -pvmwaremysql>use mysql;

mysql>update user set host = ‘%’ where user = ‘root’;

mysql>select host, user from user;

③mysql8.0 navicat可能会出现1251错误,原因是MySQL8.0版本的加密方式和MySQL5.0的不一样,连接会报错。

试了很多种方法,终于找到一种可以实现的:

mysql -uroot -p

ALTER USER ‘root’@’%t’ IDENTIFIED BY ‘你的密码’ PASSWORD EXPIRE NEVER;

重启mysql即可

百度云远程连接自己的云服务器,

作为一个菜鸟,在什么都不知道的情况下,贸然申请了个云服务器。。。。。。备案完,才知道,没有自己想象中那么简单,

首先,当时百度云搞活动,购买了个云服务器BCC,在备案完之后,以为按照网上的建站视频,可以自己建一个,但是按照步骤总有一些不同,然后发现,视频里讲的是虚拟主机BCH,

(对于百度云来说的话,BCC和BCH的资源都是独享型的。区别就在于BCH虚拟主机已经帮你配置好相关的网站环境。还有一些监控信息供你查看。而云服务器是没有的,服务器是由你自由支配的,需要什么环境就装什么环境。)

也就是说我申请的就是纯净版,啥也没有。。。。。。需要什么,自己搞定。。。。

沃德发!

没办法,一步百度一步操作,

远程操作服务器的话,在申请服务器时,会有类型选择,Windows,Ubuntu,OS什么的,

服务器为Windows版本时候,可以自己在电脑上操作,
%title插图%num

点开这个,输入自己在服务器后台管理哪儿看到的外网IP即可,就进到一个Windows服务器界面了

然后。。我觉得Ubuntu好操作吧,我改成了Ubuntu系统的,

这时候远程就不行了,

%title插图%num

啊???提示这个,因为网上百度云的资料很少,借鉴了一下阿里云的,呵呵。。。两个完全不同。。。。

然后又问的客服,

%title插图%num

Ubuntu版本是在后台中,这个VNC远程的。。。。。。

好了,随笔就这到这儿了,感觉往后还有一些坑,还是边百度边研究吧,有大佬看到的话,不妨留言一下后边怎么操作,免得小弟们一直撞南墙。。。。O(∩_∩)O哈哈~红红火火恍恍惚惚

服务器运行资源监测工具

背景说明:

对于网站服务器的硬件配置,一直以来都是一个模糊的标准,因为涉及到的硬件指标很多,比如:CPU,内存,硬盘,网络等。

写了个小程序用来记录服务器运行时资源占用的情况,本来windows自带了一个Performance性能计数器的,用C#代码也能读取到其记录的信息,不过经测试,发现windows性能计数器里的数据是准确的,但是代码读取出来的数据并不准确。后面用其他方式实现了;

%title插图%num %title插图%num

从Perforce到Git的迁移

公司经过多次兼并、收购之后,开发团队使用的工具自然会出现鱼龙混杂的现象。就拿源代码管理工具来说,我们同时在使用的就有Perforce、Team Foundation、Subversion等。为了节省成本,也为了统一工程实践(以提高工作效率),我们决定让所有团队迁移到Git。

%title插图%num

之所以选择Git,是因为:

它是主流的;
它是免费、开源的;
它支持分布式开发——这一点特别适合跨国团队;
它支持离线环境下的开发(因为每台开发机本地都有一个代码仓库depository);
它是跨平台的(支持Windows、MAC、Linux)。
Git工具可以到http://git-scm.com/上去下载。为了方便操作,也可以使用一些带图形界面的Git工具。关于Git的介绍,网上可以找到很多资料。(顺便推荐一下中文版的《Pro Git》:http://git-scm.com/book/zh。)我想在这里分享的是,我们是怎么把一大堆老项目(主要在Perforce上)迁移到Git的。(Perforce用了将近9年,终于要说“bye-bye”啦……)

在Perforce上,我们为每个产品建立了一个顶级目录。然后,在它下面分别有Main、Work、ThirdParty、Release等子目录。Main里存放一个产品的主要代码,大部分人直接在这上面工作;Work里存放一些试验性质的代码,或者自己开发的小工具;ThirdParty里存放来自第三方的SDK;而Release里存放从Main派生出来的各个版本,典型情况下是为各个客户做的定制和发布,我们一般把它们命名为RelCustomerXV1、RelCustomerXV2、RelCustomerYV1、RelCustomerZV3……整个代码结构看起来是这样的:

%title插图%num

在往Git迁移的过程中,Perforce上每个Changelist的历史记录是移不过去的(或许只是我们不知道……)。我们的办法是:在公司里仍然保留一台Perforce服务器,并开放有限的几个账号,必要时可以提供查询功能;将Perforce上*新的一份代码放到Git上去,并且以后所有的开发都在Git上进行。

我们的迁移是这么做的:首先,由管理员在Git服务器上为每个产品建立一个空的代码仓库,比如ios.git、android.git、pcmac.git等;然后,由各个产品的开发主管负责代码的上传与分支的建立。这里的焦点问题是:如何处置那些RelCustomerXXX分支?因为Perforce的分支概念与Git的有较大的区别:Perforce做的是实实在在的代码拷贝,而Git在创建分支时保存的只是指针或引用。要在Git里为每一个RelCustomerXXX创建分支吗?这样的话,服务器上的分支看起来会比较多(通过git branch -a命令查看),容易造成日后的混淆。经过团队讨论,我们*终决定把这些RelCustomerXXX都建在master上(不另外创建分支),由此带来的问题是:master的体量比较大,在开发人员*次做git clone的时候会比较耗时。忍了!

往Git上传代码的过程是在Git Bash(Windows | All Programs | Git)里通过执行一系列git命令来完成的。具体步骤如下(以iOS产品为例):

%title插图%num

假设你的工作目录(Working Directory)在D:\GitWorkspace。在运行Git Bash之后,你需要执行cd D:\GitWorkspace进入该目录。然后执行git clone命令将空的代码仓库克隆到本地:

git clone <server URL>:ios.git

克隆完成之后,执行cd命令进入本地仓库(你可以看到默认指向了master)。然后,在文件浏览器里,将Perforce上拿到的*新的产品代码拷贝到D:\GitWorkspace\ios\main中,并且在D:\GitWorkspace\ios\customer_releases\下面建立子目录、拷入各个RelCustomerXXX分支的代码,还有其他一些文件(比如work、thirdparty)都拷入D:\GitWorkspace\ios\……当所有文件都准备好之后,在Git Bash里依次执行下面的命令:

git add -A

git commit -m “the initial porting from Perforce”

git remote add origin <server URL>:ios.git

git push origin master

如果上传的代码比较多,上述过程会比较耗时。至于日后在Git上的产品开发,我们决定采用“Gitflow工作流程”。因此,在完成上述的代码上传之后,每个产品的开发主管须立即创建一个develop分支:

git branch develop
git push -u origin develop

*后,别忘了让另一个开发人员在他的机器上拉一下代码(执行git clone或git pull命令),然后试着编译一下,看看是否有部分文件遗漏了。(完)