本文整理汇总了Golang中github.com/docker/docker/nat.ParsePortSpecs函数的典型用法代码示例。如果您正苦于以下问题:Golang ParsePortSpecs函数的具体用法?Golang ParsePortSpecs怎么用?Golang ParsePortSpecs使用的例子?那么恭喜您, 这里精选的函数代码示例或许可以为您提供帮助。
在下文中一共展示了ParsePortSpecs函数的15个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于我们的系统推荐出更棒的Golang代码示例。
示例1: expose
// EXPOSE 6667/tcp 7000/tcp
//
// Expose ports for links and port mappings. This all ends up in
// b.Config.ExposedPorts for runconfig.
//
func expose(b *Builder, args []string, attributes map[string]bool, original string) error {
portsTab := args
if len(args) == 0 {
return fmt.Errorf("EXPOSE requires at least one argument")
}
if b.Config.ExposedPorts == nil {
b.Config.ExposedPorts = make(nat.PortSet)
}
ports, _, err := nat.ParsePortSpecs(append(portsTab, b.Config.PortSpecs...))
if err != nil {
return err
}
// instead of using ports directly, we build a list of ports and sort it so
// the order is consistent. This prevents cache burst where map ordering
// changes between builds
portList := make([]string, len(ports))
var i int
for port := range ports {
if _, exists := b.Config.ExposedPorts[port]; !exists {
b.Config.ExposedPorts[port] = struct{}{}
}
portList[i] = string(port)
i++
}
sort.Strings(portList)
b.Config.PortSpecs = nil
return b.commit("", b.Config.Cmd, fmt.Sprintf("EXPOSE %s", strings.Join(portList, " ")))
}
开发者ID:newsoft,项目名称:docker,代码行数:37,代码来源:dispatchers.go
示例2: TestParseNetworkOptsPublicNoPort
func TestParseNetworkOptsPublicNoPort(t *testing.T) {
ports, bindings, err := nat.ParsePortSpecs([]string{"192.168.1.100"})
if err == nil {
t.Logf("Expected error Invalid containerPort")
t.Fail()
}
if ports != nil {
t.Logf("Expected nil got %s", ports)
t.Fail()
}
if bindings != nil {
t.Logf("Expected nil got %s", bindings)
t.Fail()
}
}
开发者ID:NERSC,项目名称:docker,代码行数:16,代码来源:container_unit_test.go
示例3: TestParseNetworkOptsNegativePorts
func TestParseNetworkOptsNegativePorts(t *testing.T) {
ports, bindings, err := nat.ParsePortSpecs([]string{"192.168.1.100:-1:-1"})
if err == nil {
t.Fail()
}
t.Logf("%v", len(ports))
t.Logf("%v", bindings)
if len(ports) != 0 {
t.Logf("Expected nil got %s", len(ports))
t.Fail()
}
if len(bindings) != 0 {
t.Logf("Expected 0 got %s", len(bindings))
t.Fail()
}
}
开发者ID:NERSC,项目名称:docker,代码行数:17,代码来源:container_unit_test.go
示例4: expose
// EXPOSE 6667/tcp 7000/tcp
//
// Expose ports for links and port mappings. This all ends up in
// b.Config.ExposedPorts for runconfig.
//
func expose(b *Builder, args []string, attributes map[string]bool, original string) error {
portsTab := args
if len(args) == 0 {
return fmt.Errorf("EXPOSE requires at least one argument")
}
if err := b.BuilderFlags.Parse(); err != nil {
return err
}
if b.Config.ExposedPorts == nil {
b.Config.ExposedPorts = make(nat.PortSet)
}
ports, bindingMap, err := nat.ParsePortSpecs(append(portsTab, b.Config.PortSpecs...))
if err != nil {
return err
}
for _, bindings := range bindingMap {
if bindings[0].HostIp != "" || bindings[0].HostPort != "" {
fmt.Fprintf(b.ErrStream, " ---> Using Dockerfile's EXPOSE instruction"+
" to map host ports to container ports (ip:hostPort:containerPort) is deprecated.\n"+
" Please use -p to publish the ports.\n")
}
}
// instead of using ports directly, we build a list of ports and sort it so
// the order is consistent. This prevents cache burst where map ordering
// changes between builds
portList := make([]string, len(ports))
var i int
for port := range ports {
if _, exists := b.Config.ExposedPorts[port]; !exists {
b.Config.ExposedPorts[port] = struct{}{}
}
portList[i] = string(port)
i++
}
sort.Strings(portList)
b.Config.PortSpecs = nil
return b.commit("", b.Config.Cmd, fmt.Sprintf("EXPOSE %s", strings.Join(portList, " ")))
}
开发者ID:pbx0,项目名称:docker,代码行数:49,代码来源:dispatchers.go
示例5: CmdExpose
func (b *buildFile) CmdExpose(args string) error {
portsTab := strings.Split(args, " ")
if b.config.ExposedPorts == nil {
b.config.ExposedPorts = make(nat.PortSet)
}
ports, _, err := nat.ParsePortSpecs(append(portsTab, b.config.PortSpecs...))
if err != nil {
return err
}
for port := range ports {
if _, exists := b.config.ExposedPorts[port]; !exists {
b.config.ExposedPorts[port] = struct{}{}
}
}
b.config.PortSpecs = nil
return b.commit("", b.config.Cmd, fmt.Sprintf("EXPOSE %v", ports))
}
开发者ID:andrew2king,项目名称:docker,代码行数:19,代码来源:build.go
示例6: TestParseNetworkOptsPrivateOnly
func TestParseNetworkOptsPrivateOnly(t *testing.T) {
ports, bindings, err := nat.ParsePortSpecs([]string{"192.168.1.100::80"})
if err != nil {
t.Fatal(err)
}
if len(ports) != 1 {
t.Logf("Expected 1 got %d", len(ports))
t.FailNow()
}
if len(bindings) != 1 {
t.Logf("Expected 1 got %d", len(bindings))
t.FailNow()
}
for k := range ports {
if k.Proto() != "tcp" {
t.Logf("Expected tcp got %s", k.Proto())
t.Fail()
}
if k.Port() != "80" {
t.Logf("Expected 80 got %s", k.Port())
t.Fail()
}
b, exists := bindings[k]
if !exists {
t.Log("Binding does not exist")
t.FailNow()
}
if len(b) != 1 {
t.Logf("Expected 1 got %d", len(b))
t.FailNow()
}
s := b[0]
if s.HostPort != "" {
t.Logf("Expected \"\" got %s", s.HostPort)
t.Fail()
}
if s.HostIp != "192.168.1.100" {
t.Fail()
}
}
}
开发者ID:NERSC,项目名称:docker,代码行数:41,代码来源:container_unit_test.go
示例7: expose
// EXPOSE 6667/tcp 7000/tcp
//
// Expose ports for links and port mappings. This all ends up in
// b.Config.ExposedPorts for runconfig.
//
func expose(b *Builder, args []string, attributes map[string]bool, original string) error {
portsTab := args
if b.Config.ExposedPorts == nil {
b.Config.ExposedPorts = make(nat.PortSet)
}
ports, _, err := nat.ParsePortSpecs(append(portsTab, b.Config.PortSpecs...))
if err != nil {
return err
}
for port := range ports {
if _, exists := b.Config.ExposedPorts[port]; !exists {
b.Config.ExposedPorts[port] = struct{}{}
}
}
b.Config.PortSpecs = nil
return b.commit("", b.Config.Cmd, fmt.Sprintf("EXPOSE %v", ports))
}
开发者ID:TencentSA,项目名称:docker-1.3,代码行数:26,代码来源:dispatchers.go
示例8: migratePortMappings
func migratePortMappings(config *runconfig.Config, hostConfig *runconfig.HostConfig) error {
if config.PortSpecs != nil {
ports, bindings, err := nat.ParsePortSpecs(config.PortSpecs)
if err != nil {
return err
}
config.PortSpecs = nil
if len(bindings) > 0 {
if hostConfig == nil {
hostConfig = &runconfig.HostConfig{}
}
hostConfig.PortBindings = bindings
}
if config.ExposedPorts == nil {
config.ExposedPorts = make(nat.PortSet, len(ports))
}
for k, v := range ports {
config.ExposedPorts[k] = v
}
}
return nil
}
开发者ID:Gandi,项目名称:docker,代码行数:23,代码来源:utils.go
示例9: Parse
//.........这里部分代码省略.........
} else if bind == "/" {
return nil, nil, cmd, fmt.Errorf("Invalid volume: path can't be '/'")
}
}
var (
parsedArgs = cmd.Args()
runCmd []string
entrypoint []string
image = cmd.Arg(0)
)
if len(parsedArgs) > 1 {
runCmd = parsedArgs[1:]
}
if *flEntrypoint != "" {
entrypoint = []string{*flEntrypoint}
}
lxcConf, err := parseKeyValueOpts(flLxcOpts)
if err != nil {
return nil, nil, cmd, err
}
var (
domainname string
hostname = *flHostname
parts = strings.SplitN(hostname, ".", 2)
)
if len(parts) > 1 {
hostname = parts[0]
domainname = parts[1]
}
ports, portBindings, err := nat.ParsePortSpecs(flPublish.GetAll())
if err != nil {
return nil, nil, cmd, err
}
// Merge in exposed ports to the map of published ports
for _, e := range flExpose.GetAll() {
if strings.Contains(e, ":") {
return nil, nil, cmd, fmt.Errorf("Invalid port format for --expose: %s", e)
}
//support two formats for expose, original format <portnum>/[<proto>] or <startport-endport>/[<proto>]
proto, port := nat.SplitProtoPort(e)
//parse the start and end port and create a sequence of ports to expose
//if expose a port, the start and end port are the same
start, end, err := parsers.ParsePortRange(port)
if err != nil {
return nil, nil, cmd, fmt.Errorf("Invalid range format for --expose: %s, error: %s", e, err)
}
for i := start; i <= end; i++ {
p := nat.NewPort(proto, strconv.FormatUint(i, 10))
if _, exists := ports[p]; !exists {
ports[p] = struct{}{}
}
}
}
// parse device mappings
deviceMappings := []DeviceMapping{}
for _, device := range flDevices.GetAll() {
deviceMapping, err := ParseDevice(device)
if err != nil {
return nil, nil, cmd, err
}
开发者ID:pombredanne,项目名称:docker,代码行数:67,代码来源:parse.go
示例10: TestMerge
func TestMerge(t *testing.T) {
volumesImage := make(map[string]struct{})
volumesImage["/test1"] = struct{}{}
volumesImage["/test2"] = struct{}{}
configImage := &Config{
PortSpecs: []string{"1111:1111", "2222:2222"},
Env: []string{"VAR1=1", "VAR2=2"},
Volumes: volumesImage,
}
volumesUser := make(map[string]struct{})
volumesUser["/test3"] = struct{}{}
configUser := &Config{
PortSpecs: []string{"3333:2222", "3333:3333"},
Env: []string{"VAR2=3", "VAR3=3"},
Volumes: volumesUser,
}
if err := Merge(configUser, configImage); err != nil {
t.Error(err)
}
if len(configUser.ExposedPorts) != 3 {
t.Fatalf("Expected 3 ExposedPorts, 1111, 2222 and 3333, found %d", len(configUser.ExposedPorts))
}
for portSpecs := range configUser.ExposedPorts {
if portSpecs.Port() != "1111" && portSpecs.Port() != "2222" && portSpecs.Port() != "3333" {
t.Fatalf("Expected 1111 or 2222 or 3333, found %s", portSpecs)
}
}
if len(configUser.Env) != 3 {
t.Fatalf("Expected 3 env var, VAR1=1, VAR2=3 and VAR3=3, found %d", len(configUser.Env))
}
for _, env := range configUser.Env {
if env != "VAR1=1" && env != "VAR2=3" && env != "VAR3=3" {
t.Fatalf("Expected VAR1=1 or VAR2=3 or VAR3=3, found %s", env)
}
}
if len(configUser.Volumes) != 3 {
t.Fatalf("Expected 3 volumes, /test1, /test2 and /test3, found %d", len(configUser.Volumes))
}
for v := range configUser.Volumes {
if v != "/test1" && v != "/test2" && v != "/test3" {
t.Fatalf("Expected /test1 or /test2 or /test3, found %s", v)
}
}
ports, _, err := nat.ParsePortSpecs([]string{"0000"})
if err != nil {
t.Error(err)
}
configImage2 := &Config{
ExposedPorts: ports,
}
if err := Merge(configUser, configImage2); err != nil {
t.Error(err)
}
if len(configUser.ExposedPorts) != 4 {
t.Fatalf("Expected 4 ExposedPorts, 0000, 1111, 2222 and 3333, found %d", len(configUser.ExposedPorts))
}
for portSpecs := range configUser.ExposedPorts {
if portSpecs.Port() != "0" && portSpecs.Port() != "1111" && portSpecs.Port() != "2222" && portSpecs.Port() != "3333" {
t.Fatalf("Expected %q or %q or %q or %q, found %s", 0, 1111, 2222, 3333, portSpecs)
}
}
}
开发者ID:hgschmie,项目名称:docker,代码行数:70,代码来源:config_test.go
示例11: Parse
//.........这里部分代码省略.........
}
var (
parsedArgs = cmd.Args()
runCmd []string
entrypoint []string
image string
)
if len(parsedArgs) >= 1 {
image = cmd.Arg(0)
}
if len(parsedArgs) > 1 {
runCmd = parsedArgs[1:]
}
if *flEntrypoint != "" {
entrypoint = []string{*flEntrypoint}
}
lxcConf, err := parseKeyValueOpts(flLxcOpts)
if err != nil {
return nil, nil, cmd, err
}
var (
domainname string
hostname = *flHostname
parts = strings.SplitN(hostname, ".", 2)
)
if len(parts) > 1 {
hostname = parts[0]
domainname = parts[1]
}
ports, portBindings, err := nat.ParsePortSpecs(flPublish.GetAll())
if err != nil {
return nil, nil, cmd, err
}
// Merge in exposed ports to the map of published ports
for _, e := range flExpose.GetAll() {
if strings.Contains(e, ":") {
return nil, nil, cmd, fmt.Errorf("Invalid port format for --expose: %s", e)
}
p := nat.NewPort(nat.SplitProtoPort(e))
if _, exists := ports[p]; !exists {
ports[p] = struct{}{}
}
}
// parse device mappings
deviceMappings := []DeviceMapping{}
for _, device := range flDevices.GetAll() {
deviceMapping, err := ParseDevice(device)
if err != nil {
return nil, nil, cmd, err
}
deviceMappings = append(deviceMappings, deviceMapping)
}
// collect all the environment variables for the container
envVariables := []string{}
for _, ef := range flEnvFile.GetAll() {
parsedVars, err := opts.ParseEnvFile(ef)
if err != nil {
return nil, nil, cmd, err
}
开发者ID:TencentSA,项目名称:docker-1.3,代码行数:67,代码来源:parse.go
示例12: Merge
func Merge(userConf, imageConf *Config) error {
if userConf.User == "" {
userConf.User = imageConf.User
}
if len(userConf.ExposedPorts) == 0 {
userConf.ExposedPorts = imageConf.ExposedPorts
} else if imageConf.ExposedPorts != nil {
if userConf.ExposedPorts == nil {
userConf.ExposedPorts = make(nat.PortSet)
}
for port := range imageConf.ExposedPorts {
if _, exists := userConf.ExposedPorts[port]; !exists {
userConf.ExposedPorts[port] = struct{}{}
}
}
}
if len(userConf.PortSpecs) > 0 {
if userConf.ExposedPorts == nil {
userConf.ExposedPorts = make(nat.PortSet)
}
ports, _, err := nat.ParsePortSpecs(userConf.PortSpecs)
if err != nil {
return err
}
for port := range ports {
if _, exists := userConf.ExposedPorts[port]; !exists {
userConf.ExposedPorts[port] = struct{}{}
}
}
userConf.PortSpecs = nil
}
if len(imageConf.PortSpecs) > 0 {
// FIXME: I think we can safely remove this. Leaving it for now for the sake of reverse-compat paranoia.
logrus.Debugf("Migrating image port specs to containter: %s", strings.Join(imageConf.PortSpecs, ", "))
if userConf.ExposedPorts == nil {
userConf.ExposedPorts = make(nat.PortSet)
}
ports, _, err := nat.ParsePortSpecs(imageConf.PortSpecs)
if err != nil {
return err
}
for port := range ports {
if _, exists := userConf.ExposedPorts[port]; !exists {
userConf.ExposedPorts[port] = struct{}{}
}
}
}
if len(userConf.Env) == 0 {
userConf.Env = imageConf.Env
} else {
for _, imageEnv := range imageConf.Env {
found := false
imageEnvKey := strings.Split(imageEnv, "=")[0]
for _, userEnv := range userConf.Env {
userEnvKey := strings.Split(userEnv, "=")[0]
if imageEnvKey == userEnvKey {
found = true
}
}
if !found {
userConf.Env = append(userConf.Env, imageEnv)
}
}
}
if userConf.Labels == nil {
userConf.Labels = map[string]string{}
}
if imageConf.Labels != nil {
for l := range userConf.Labels {
imageConf.Labels[l] = userConf.Labels[l]
}
userConf.Labels = imageConf.Labels
}
if userConf.Entrypoint.Len() == 0 {
if userConf.Cmd.Len() == 0 {
userConf.Cmd = imageConf.Cmd
}
if userConf.Entrypoint == nil {
userConf.Entrypoint = imageConf.Entrypoint
}
}
if userConf.WorkingDir == "" {
userConf.WorkingDir = imageConf.WorkingDir
}
if len(userConf.Volumes) == 0 {
userConf.Volumes = imageConf.Volumes
} else {
for k, v := range imageConf.Volumes {
userConf.Volumes[k] = v
}
}
return nil
}
开发者ID:yckrasnodar,项目名称:docker,代码行数:99,代码来源:merge.go
示例13: Convert
func Convert(c *project.ServiceConfig) (*runconfig.Config, *runconfig.HostConfig, error) {
vs := Filter(c.Volumes, isVolume)
volumes := make(map[string]struct{}, len(vs))
for _, v := range vs {
volumes[v] = struct{}{}
}
cmd, _ := shlex.Split(c.Command)
entrypoint, _ := shlex.Split(c.Entrypoint)
ports, binding, err := nat.ParsePortSpecs(c.Ports)
if err != nil {
return nil, nil, err
}
restart, err := runconfig.ParseRestartPolicy(c.Restart)
if err != nil {
return nil, nil, err
}
dns := c.Dns.Slice()
dnssearch := c.DnsSearch.Slice()
labels := c.Labels.MapParts()
if len(c.Expose) > 0 {
exposedPorts, _, err := nat.ParsePortSpecs(c.Expose)
ports = exposedPorts
if err != nil {
return nil, nil, err
}
}
config := &runconfig.Config{
Entrypoint: runconfig.NewEntrypoint(entrypoint...),
Hostname: c.Hostname,
Domainname: c.DomainName,
User: c.User,
Env: c.Environment.Slice(),
Cmd: runconfig.NewCommand(cmd...),
Image: c.Image,
Labels: labels,
ExposedPorts: ports,
Tty: c.Tty,
OpenStdin: c.StdinOpen,
WorkingDir: c.WorkingDir,
Volumes: volumes,
}
host_config := &runconfig.HostConfig{
VolumesFrom: c.VolumesFrom,
CapAdd: c.CapAdd,
CapDrop: c.CapDrop,
CpuShares: c.CpuShares,
Privileged: c.Privileged,
Binds: Filter(c.Volumes, isBind),
Dns: dns,
DnsSearch: dnssearch,
LogConfig: runconfig.LogConfig{
Type: c.LogDriver,
},
Memory: c.MemLimit,
NetworkMode: runconfig.NetworkMode(c.Net),
ReadonlyRootfs: c.ReadOnly,
PidMode: runconfig.PidMode(c.Pid),
IpcMode: runconfig.IpcMode(c.Ipc),
PortBindings: binding,
RestartPolicy: restart,
}
return config, host_config, nil
}
开发者ID:jgatkinsn,项目名称:os,代码行数:68,代码来源:convert.go
示例14: Convert
func Convert(c *project.ServiceConfig) (*runconfig.Config, *runconfig.HostConfig, error) {
vs := Filter(c.Volumes, isVolume)
volumes := make(map[string]struct{}, len(vs))
for _, v := range vs {
volumes[v] = struct{}{}
}
ports, binding, err := nat.ParsePortSpecs(c.Ports)
if err != nil {
return nil, nil, err
}
restart, err := runconfig.ParseRestartPolicy(c.Restart)
if err != nil {
return nil, nil, err
}
if exposedPorts, _, err := nat.ParsePortSpecs(c.Expose); err != nil {
return nil, nil, err
} else {
for k, v := range exposedPorts {
ports[k] = v
}
}
deviceMappings, err := parseDevices(c.Devices)
if err != nil {
return nil, nil, err
}
config := &runconfig.Config{
Entrypoint: runconfig.NewEntrypoint(c.Entrypoint.Slice()...),
Hostname: c.Hostname,
Domainname: c.DomainName,
User: c.User,
Env: c.Environment.Slice(),
Cmd: runconfig.NewCommand(c.Command.Slice()...),
Image: c.Image,
Labels: c.Labels.MapParts(),
ExposedPorts: ports,
Tty: c.Tty,
OpenStdin: c.StdinOpen,
WorkingDir: c.WorkingDir,
VolumeDriver: c.VolumeDriver,
Volumes: volumes,
}
host_config := &runconfig.HostConfig{
VolumesFrom: c.VolumesFrom,
CapAdd: c.CapAdd,
CapDrop: c.CapDrop,
CpuShares: c.CpuShares,
CpusetCpus: c.CpuSet,
ExtraHosts: c.ExtraHosts,
Privileged: c.Privileged,
Binds: Filter(c.Volumes, isBind),
Devices: deviceMappings,
Dns: c.Dns.Slice(),
DnsSearch: c.DnsSearch.Slice(),
LogConfig: runconfig.LogConfig{
Type: c.LogDriver,
Config: c.LogOpt,
},
Memory: c.MemLimit,
MemorySwap: c.MemSwapLimit,
NetworkMode: runconfig.NetworkMode(c.Net),
ReadonlyRootfs: c.ReadOnly,
PidMode: runconfig.PidMode(c.Pid),
UTSMode: runconfig.UTSMode(c.Uts),
IpcMode: runconfig.IpcMode(c.Ipc),
PortBindings: binding,
RestartPolicy: restart,
SecurityOpt: c.SecurityOpt,
}
return config, host_config, nil
}
开发者ID:kloudsio,项目名称:rancher-compose,代码行数:76,代码来源:convert.go
示例15: Parse
//.........这里部分代码省略.........
return nil, nil, cmd, fmt.Errorf("Invalid volume: path can't be '/'")
}
}
var (
parsedArgs = cmd.Args()
runCmd *Command
entrypoint *Entrypoint
image = cmd.Arg(0)
)
if len(parsedArgs) > 1 {
runCmd = NewCommand(parsedArgs[1:]...)
}
if *flEntrypoint != "" {
entrypoint = NewEntrypoint(*flEntrypoint)
}
lc, err := parseKeyValueOpts(flLxcOpts)
if err != nil {
return nil, nil, cmd, err
}
lxcConf := NewLxcConfig(lc)
var (
domainname string
hostname = *flHostname
parts = strings.SplitN(hostname, ".", 2)
)
if len(parts) > 1 {
hostname = parts[0]
domainname = parts[1]
}
ports, portBindings, err := nat.ParsePortSpecs(flPublish.GetAll())
if err != nil {
return nil, nil, cmd, err
}
// Merge in exposed ports to the map of published ports
for _, e := range flExpose.GetAll() {
if strings.Contains(e, ":") {
return nil, nil, cmd, fmt.Errorf("Invalid port format for --expose: %s", e)
}
//support two formats for expose, original format <portnum>/[<proto>] or <startport-endport>/[<proto>]
proto, port := nat.SplitProtoPort(e)
//parse the start and end port and create a sequence of ports to expose
//if expose a port, the start and end port are the same
start, end, err := parsers.ParsePortRange(port)
if err != nil {
return nil, nil, cmd, fmt.Errorf("Invalid range format for --expose: %s, error: %s", e, err)
}
for i := start; i <= end; i++ {
p := nat.NewPort(proto, strconv.FormatUint(i, 10))
if _, exists := ports[p]; !exists {
ports[p] = struct{}{}
}
}
}
// parse device mappings
deviceMappings := []DeviceMapping{}
for _, device := range flDevices.GetAll() {
deviceMapping, err := ParseDevice(device)
if err != nil {
return nil, nil, cmd, err
}
开发者ID:sheavner,项目名称:docker,代码行数:67,代码来源:parse.go
注:本文中的github.com/docker/docker/nat.ParsePortSpecs函数示例整理自Github/MSDocs等源码及文档管理平台,相关代码片段筛选自各路编程大神贡献的开源项目,源码版权归原作者所有,传播和使用请参考对应项目的License;未经允许,请勿转载。 |
请发表评论